﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Создание сообщения по шаблону
// Параметры:
//  ПараметрыОтправки - Структура:
//    * ДополнительныеПараметры - Структура
//
// Возвращаемое значение:
//   Структура:
//   * Вложения - ТаблицаЗначений:
//     ** Представление - Строка
//     ** АдресВоВременномХранилище - Строка
//     ** Кодировка - Строка
//     ** Идентификатор - Строка
//   * СообщенияПользователю - ФиксированныйМассив
//   * ДополнительныеПараметры - Структура:
//     ** Отправитель - Строка
//   * Получатель - Неопределено
//   * Текст - Строка
//   * Тема - Строка
//
Функция СформироватьСообщение(ПараметрыОтправки) Экспорт
	
	Если ПараметрыОтправки.Шаблон = Справочники.ШаблоныСообщений.ПустаяСсылка() Тогда
		Возврат СообщениеБезШаблона(ПараметрыОтправки);
	КонецЕсли;
	
	ПараметрыШаблона = ПараметрыШаблона(ПараметрыОтправки.Шаблон);
	Если ПараметрыОтправки.ДополнительныеПараметры.Свойство("ПараметрыСообщения") Тогда
		ПараметрыШаблона.ПараметрыСообщения = ПараметрыОтправки.ДополнительныеПараметры.ПараметрыСообщения;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПараметрыОтправки.ДополнительныеПараметры.ЗначенияПараметровСКД) Тогда
		ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ПараметрыШаблона.ПараметрыСКД,
			ПараметрыОтправки.ДополнительныеПараметры.ЗначенияПараметровСКД, Истина);
	КонецЕсли;
	
	Если ПараметрыОтправки.Шаблон = Неопределено Тогда
		Если ПараметрыОтправки.Свойство("ДополнительныеПараметры")
			И ПараметрыОтправки.ДополнительныеПараметры.Свойство("ВидСообщения") Тогда
			ПараметрыШаблона.ТипШаблона = ПараметрыОтправки.ДополнительныеПараметры.ВидСообщения;
		КонецЕсли;
	Иначе
		ПредназначенДляSMS = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(ПараметрыОтправки.Шаблон, "ПредназначенДляSMS");
		Если ПредназначенДляSMS <> Истина Тогда
			ПараметрыОтправки.ДополнительныеПараметры.Вставить("ВидСообщения", "ЭлектроннаяПочта");
		Иначе
			ПараметрыОтправки.ДополнительныеПараметры.Вставить("ВидСообщения", "СообщениеSMS");
		КонецЕсли;
	КонецЕсли;
	
	МенеджерОбъекта = Неопределено;
	СведенияОШаблоне = Неопределено;
	Если ПараметрыОтправки.Предмет <> Неопределено Тогда
		СведенияОШаблоне = СведенияОШаблоне(ПараметрыШаблона);
		ПараметрыШаблона.Вставить("Предмет", ПараметрыОтправки.Предмет);
	КонецЕсли;
	Если ЗначениеЗаполнено(ПараметрыШаблона.ПолноеИмяТипаНазначения) Тогда
		МетаданныеОбъекта = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПараметрыШаблона.ПолноеИмяТипаНазначения);
		Если МетаданныеОбъекта <> Неопределено Тогда
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПараметрыШаблона.ПолноеИмяТипаНазначения);
		КонецЕсли;
	КонецЕсли;
	
	СформированноеСообщение = КонструкторСообщения(ПараметрыШаблона);
	Если ПараметрыШаблона = Неопределено Тогда
		Возврат СформированноеСообщение;
	КонецЕсли;
	
	Если ПараметрыШаблона.ШаблонПоВнешнейОбработке Тогда
		Возврат СформироватьСообщениеВнешнейОбработкой(ПараметрыШаблона, СведенияОШаблоне, ПараметрыОтправки);
	КонецЕсли;
	
	// Извлекаем из шаблона параметры
	ПараметрыТекстаСообщения = ПараметрыИзТекстаСообщения(ПараметрыШаблона);
	
	// Заполняем параметры
	Сообщение = ЗаполнитьПараметрыСообщения(ПараметрыШаблона, ПараметрыТекстаСообщения, ПараметрыОтправки);
	Сообщение.ДополнительныеПараметры = ПараметрыОтправки.ДополнительныеПараметры;
	
	// Вложения
	Если ПараметрыШаблона.ТипШаблона = "Письмо" И СведенияОШаблоне <> Неопределено Тогда
		ДобавитьВыбранныеПечатныеФормыВоВложения(ПараметрыОтправки, СведенияОШаблоне, Сообщение.Вложения, ПараметрыШаблона);
	КонецЕсли;
	ДобавитьПрисоединенныеФайлыВоВложения(ПараметрыОтправки, Сообщение);
	
	ШаблоныСообщенийПереопределяемый.ПриФормированииСообщения(Сообщение, ПараметрыШаблона.ПолноеИмяТипаНазначения, ПараметрыОтправки.Предмет, ПараметрыШаблона);
	Если МенеджерОбъекта <> Неопределено Тогда
		МенеджерОбъекта.ПриФормированииСообщения(Сообщение, ПараметрыОтправки.Предмет, ПараметрыШаблона);
	КонецЕсли;
	
	// Заполнение значений параметров
	СообщениеРезультат = УстановитьЗначенияРеквизитовВТекстСообщения(ПараметрыШаблона, ПараметрыТекстаСообщения, ПараметрыОтправки.Предмет);
	
	СформированноеСообщение.Тема  = СообщениеРезультат.Тема;
	СформированноеСообщение.Текст = СообщениеРезультат.Текст;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");
	
	Если ПараметрыШаблона.ДобавлятьПрисоединенныеФайлы Тогда
			
			ФайлыВладельца = Новый Массив;
			МодульРаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(ПараметрыОтправки.Предмет, ФайлыВладельца);
			Для Каждого ФайлВладельца Из ФайлыВладельца Цикл
				ДанныеФайла = МодульРаботаСФайлами.ДанныеФайла(ФайлВладельца);
				Если ДанныеФайла = Неопределено Или ДанныеФайла.Количество() = 0 Тогда
					Продолжить;
				КонецЕсли;
				
				НовоеВложение = СформированноеСообщение.Вложения.Добавить();
				НовоеВложение.АдресВоВременномХранилище = ДанныеФайла.СсылкаНаДвоичныеДанныеФайла;
				НовоеВложение.Представление =?(ПараметрыШаблона.ТранслитерироватьИменаФайлов,
					 СтроковыеФункции.СтрокаЛатиницей(ДанныеФайла.ИмяФайла), ДанныеФайла.ИмяФайла);
				
			КонецЦикла;
			
		КонецЕсли;
	
	КонецЕсли;
	
	Для каждого Вложение Из Сообщение.Вложения Цикл
		НовоеВложение = СформированноеСообщение.Вложения.Добавить();
		Если ПараметрыШаблона.ТранслитерироватьИменаФайлов Тогда
			НовоеВложение.Представление = СтроковыеФункции.СтрокаЛатиницей(Вложение.Ключ);
		Иначе
			НовоеВложение.Представление = Вложение.Ключ;
		КонецЕсли;
		НовоеВложение.АдресВоВременномХранилище = Вложение.Значение;
	КонецЦикла;
	
	Если ПараметрыШаблона.ТипШаблона = "Письмо" И ПараметрыШаблона.ФорматПисьма = Перечисления.СпособыРедактированияЭлектронныхПисем.HTML Тогда
		ОбработатьHTMLДляФорматированногоДокумента(ПараметрыОтправки, СформированноеСообщение, ПараметрыОтправки.ДополнительныеПараметры.ПреобразовыватьHTMLДляФорматированногоДокумента);
	КонецЕсли;
	
	ЗаполнитьПолучателейСообщения(ПараметрыОтправки, ПараметрыШаблона, СформированноеСообщение, МенеджерОбъекта);
	СформированноеСообщение.СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
	
	Возврат СформированноеСообщение;
	
КонецФункции

// Сформировать сообщение и сразу отправить.
// 
// Параметры:
//   ПараметрыОтправки - Структура:
//   * ДополнительныеПараметры - Структура
//
// Возвращаемое значение:
//    см. РезультатОтправкиПисьма
// 
Функция СформироватьСообщениеИОтправить(ПараметрыОтправки) Экспорт
	
	Результат = РезультатОтправкиПисьма();
	
	Сообщение = СформироватьСообщение(ПараметрыОтправки);
	
	Если ПараметрыОтправки.Шаблон.ПредназначенДляSMS Тогда
		Если Сообщение.Получатель.Количество() = 0 Тогда
			Результат.ОписаниеОшибки  = НСтр("ru = 'Для отправки сообщения введите номера телефонов получателей.'");
			Возврат Результат;
		КонецЕсли;
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ОтправкаSMS") Тогда
			МодульОтправкаSMS = ОбщегоНазначения.ОбщийМодуль("ОтправкаSMS");
			Если МодульОтправкаSMS.ДоступнаОтправкаSMS() Тогда
				
				Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Взаимодействия") Тогда
					
					МодульВзаимодействия = ОбщегоНазначения.ОбщийМодуль("Взаимодействия");
					Если МодульВзаимодействия.ИспользуютсяПрочиеВзаимодействия() Тогда
						
						МодульВзаимодействия.СоздатьИОтправитьСообщениеSMS(Сообщение);
						Результат.Отправлено = Истина;
						Возврат Результат;
						
					КонецЕсли;
				КонецЕсли;
				
				НомераПолучателей = Новый Массив;
				Для каждого Получатель Из Сообщение.Получатель Цикл
					Если ТипЗнч(Получатель) = Тип("Структура") Тогда
						НомераПолучателей.Добавить(Получатель.НомерТелефона);
					Иначе
						НомераПолучателей.Добавить(Получатель.Значение);
					КонецЕсли;
				КонецЦикла;
				
				РезультатОтправкаSMS = МодульОтправкаSMS.ОтправитьSMS(НомераПолучателей, Сообщение.Текст, Сообщение.ДополнительныеПараметры.Отправитель, Сообщение.ДополнительныеПараметры.ПеревестиВТранслит);
				Результат.Отправлено = ПустаяСтрока(РезультатОтправкаSMS.ОписаниеОшибки);
				Результат.ОписаниеОшибки = РезультатОтправкаSMS.ОписаниеОшибки;
				
			Иначе
				
				Результат.ОписаниеОшибки = НСтр("ru = 'Сообщение SMS не может быть отправлено сразу.'");
				
			КонецЕсли;
			
			Возврат Результат;
			
		КонецЕсли;
		
	Иначе
		Если Сообщение.Получатель.Количество() = 0 Тогда
			Результат.ОписаниеОшибки  = НСтр("ru = 'Введите адрес электронной почты, чтобы отправить сообщение сразу.'");
			Возврат Результат;
		КонецЕсли;
		
		ПараметрыПисьма = Новый Структура();
		ПараметрыПисьма.Вставить("Тема",      Сообщение.Тема);
		ПараметрыПисьма.Вставить("Тело",      Сообщение.Текст);
		ПараметрыПисьма.Вставить("Вложения",  Новый Соответствие);
		ПараметрыПисьма.Вставить("Кодировка", "utf-8");
		
		Для каждого Вложение Из Сообщение.Вложения Цикл
			НовоеВложение = Новый Структура("ДвоичныеДанные, Идентификатор");
			НовоеВложение.ДвоичныеДанные = ПолучитьИзВременногоХранилища(Вложение.АдресВоВременномХранилище);
			НовоеВложение.Идентификатор = Вложение.Идентификатор;
			ПараметрыПисьма.Вложения.Вставить(Вложение.Представление, НовоеВложение);
		КонецЦикла;
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСПочтовымиСообщениями") Тогда
			МодульРаботаСПочтовымиСообщениямиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениямиСлужебный");
			Если Сообщение.ДополнительныеПараметры.ФорматПисьма = Перечисления.СпособыРедактированияЭлектронныхПисем.HTML Тогда
				ТипТекста = МодульРаботаСПочтовымиСообщениямиСлужебный.ТипТекстовЭлектронныхПисем("HTMLСКартинками");
			Иначе
				ТипТекста = МодульРаботаСПочтовымиСообщениямиСлужебный.ТипТекстовЭлектронныхПисем("ПростойТекст");
			КонецЕсли;
		Иначе
			ТипТекста = "";
		КонецЕсли;
		
		ПараметрыПисьма.Вставить("ТипТекста", ТипТекста);
		Кому = СформироватьСписокПолучателейСообщения(Сообщение.Получатель);
		
		ПараметрыПисьма.Вставить("Кому", Кому);
		
		Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСПочтовымиСообщениями") Тогда
			МодульРаботаСПочтовымиСообщениями = ОбщегоНазначения.ОбщийМодуль("РаботаСПочтовымиСообщениями");
			Если МодульРаботаСПочтовымиСообщениями.ДоступнаОтправкаПисем() Тогда
				
				Если ПараметрыОтправки.ДополнительныеПараметры.УчетнаяЗапись = Неопределено Тогда
					УчетнаяЗапись = МодульРаботаСПочтовымиСообщениями.СистемнаяУчетнаяЗапись();
				Иначе
					УчетнаяЗапись = ПараметрыОтправки.ДополнительныеПараметры.УчетнаяЗапись;
				КонецЕсли;
				
				Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Взаимодействия") Тогда
					
					МодульВзаимодействия = ОбщегоНазначения.ОбщийМодуль("Взаимодействия");
					Если МодульВзаимодействия.ИспользуетсяПочтовыйКлиент() Тогда
						
						ПараметрыПисьма = МодульВзаимодействия.ПараметрыПисьма();
						ЗаполнитьЗначенияСвойств(ПараметрыПисьма, Сообщение, , "ДополнительныеПараметры");
						
						СписокПолучателейСпискомЗначений =(ТипЗнч(Сообщение.Получатель) = Тип("СписокЗначений"));
						Для Каждого ПолучательПисьма Из Сообщение.Получатель Цикл
							НоваяСтрока = ПараметрыПисьма.Получатели.Добавить();
							Если СписокПолучателейСпискомЗначений Тогда
								НоваяСтрока.Адрес         = ПолучательПисьма.Значение;
								НоваяСтрока.Представление = ПолучательПисьма.Представление;
							Иначе
								НоваяСтрока.Адрес         = ПолучательПисьма.Адрес;
								НоваяСтрока.Представление = ПолучательПисьма.Представление;
								НоваяСтрока.ИсточникКонтактнойИнформации = ПолучательПисьма.ИсточникКонтактнойИнформации;
							КонецЕсли;
						КонецЦикла;
						
						ЗаполнитьЗначенияСвойств(ПараметрыПисьма.ДополнительныеПараметры, Сообщение.ДополнительныеПараметры);
						ПараметрыПисьма.ДополнительныеПараметры.Комментарий = КомментарийПоНаименованиюШаблона(Сообщение.ДополнительныеПараметры.Наименование);
						
						РезультатОтправки = МодульВзаимодействия.СоздатьПисьмо(ПараметрыПисьма, УчетнаяЗапись, ПараметрыОтправки.ДополнительныеПараметры.ОтправитьСразу);
						ЗаполнитьЗначенияСвойств(Результат, РезультатОтправки);
						Возврат Результат;
						
					КонецЕсли;
					
				КонецЕсли;
				
				Письмо = МодульРаботаСПочтовымиСообщениями.ПодготовитьПисьмо(УчетнаяЗапись, ПараметрыПисьма);
				МодульРаботаСПочтовымиСообщениями.ОтправитьПисьмо(УчетнаяЗапись, Письмо);
				
				Результат.Отправлено = Истина;
				
			Иначе
				
				Результат.ОписаниеОшибки  = НСтр("ru = 'Сообщение не может быть отправлено сразу.'");
				Возврат Результат;
				
			КонецЕсли;
		КонецЕсли
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ЕстьДоступныеШаблоны(ТипШаблона, Предмет = Неопределено) Экспорт
	
	Если Не ПравоДоступа("Чтение", Метаданные.Справочники.ШаблоныСообщений) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Запрос = ПодготовитьЗапросДляПолученияСпискаШаблонов(ТипШаблона, Предмет);
	Возврат НЕ Запрос.Выполнить().Пустой();
КонецФункции

// Возвращает список объектов метаданных к которым подключена подсистема Шаблоны сообщений.
//
// Возвращаемое значение:
//  Массив - список из элементов типа ОбъектМетаданных.
//
Функция ИсточникиШаблоновСообщений() Экспорт
	
	МассивТиповИлиМетаданных = Метаданные.ОпределяемыеТипы.ПредметШаблонаСообщения.Тип.Типы();
	
	ИндексТипаИдентификаторыОбъектовМетаданных = МассивТиповИлиМетаданных.Найти(Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных"));
	Если ИндексТипаИдентификаторыОбъектовМетаданных <> Неопределено Тогда
		МассивТиповИлиМетаданных.Удалить(ИндексТипаИдентификаторыОбъектовМетаданных);
	КонецЕсли;
	
	Возврат МассивТиповИлиМетаданных;
	
КонецФункции

Функция ИспользуютсяШаблоныСообщений() Экспорт
	Возврат ПолучитьФункциональнуюОпцию("ИспользоватьШаблоныСообщений");
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистем конфигурации.

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.0.1.35";
	Обработчик.Процедура = "ШаблоныСообщенийСлужебный.ДобавитьРольДобавлениеИзменениеЛичныхШаблоновВПрофилиСБазовымиПравами";
	Обработчик.РежимВыполнения = "Оперативно";
	
	ЧитаемыеОбъекты = Новый Массив;
	ЧитаемыеОбъекты.Добавить("Справочник.ШаблоныСообщений");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		ЧитаемыеОбъекты.Добавить(Метаданные.Справочники["ВидыКонтактнойИнформации"].ПолноеИмя());
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		ЧитаемыеОбъекты.Добавить(Метаданные.Справочники["ДополнительныеОтчетыИОбработки"].ПолноеИмя());
	КонецЕсли;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия          = "3.1.3.156";
	Обработчик.Идентификатор   = Новый УникальныйИдентификатор("9fa8ac0b-1d3c-4584-8d32-bb46720e9d67");
	Обработчик.Процедура       = "Справочники.ШаблоныСообщений.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ШаблоныСообщений.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты    = СтрСоединить(ЧитаемыеОбъекты, ",");
	Обработчик.ИзменяемыеОбъекты  = "Справочник.ШаблоныСообщений";
	Обработчик.БлокируемыеОбъекты = "Справочник.ШаблоныСообщений";
	Обработчик.ПроцедураПроверки  = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Обработчик.Комментарий = НСтр("ru = 'Обновление шаблонов сообщений.
		|До завершения обработки формирование писем и сообщений SMS на основании шаблонов будет недоступно.'");
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
		Приоритет = Обработчик.ПриоритетыВыполнения.Добавить();
		Приоритет.Процедура = "Справочники.ВидыКонтактнойИнформации.ОбработатьДанныеДляПереходаНаНовуюВерсию";
		Приоритет.Порядок = "После";
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Мультиязычность") Тогда
		
		Если Обработчик.ПриоритетыВыполнения = Неопределено Тогда
			Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
		КонецЕсли;
		
		Приоритет = Обработчик.ПриоритетыВыполнения.Добавить();
		Приоритет.Процедура = "МультиязычностьСервер.ОбработатьДанныеДляПереходаНаНовуюВерсию";
		Приоритет.Порядок = "До";
	КонецЕсли;
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииСписковСОграничениемДоступа.
Процедура ПриЗаполненииСписковСОграничениемДоступа(Списки) Экспорт
	
	Списки.Вставить(Метаданные.Справочники.ШаблоныСообщений, Истина);
	Списки.Вставить(Метаданные.Справочники.ШаблоныСообщенийПрисоединенныеФайлы, Истина);
	
КонецПроцедуры

// См. УправлениеДоступомПереопределяемый.ПриЗаполненииВидовОграниченийПравОбъектовМетаданных.
Процедура ПриЗаполненииВидовОграниченийПравОбъектовМетаданных(Описание) Экспорт
	
	Описание = Описание + "
	|Справочник.ШаблоныСообщений.Чтение.Пользователи
	|Справочник.ШаблоныСообщений.Изменение.Пользователи
	|";
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		Описание = Описание + "
			|Справочник.ШаблоныСообщенийПрисоединенныеФайлы.Чтение.Пользователи
			|Справочник.ШаблоныСообщенийПрисоединенныеФайлы.Изменение.Пользователи
			|";
	КонецЕсли;
	
КонецПроцедуры

// Смотри также ОбновлениеИнформационнойБазыПереопределяемый.ПриОпределенииНастроек
//
// Параметры:
//  Объекты - Массив из ОбъектМетаданных
//
Процедура ПриОпределенииОбъектовСНачальнымЗаполнением(Объекты) Экспорт
	
	Объекты.Добавить(Метаданные.Справочники.ШаблоныСообщений);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращает сведения об сформированном исходящем письме. 
//
// Возвращаемое значение:
//  Структура:
//   * Отправлено - Булево - признак того, что письмо отправлено.
//   * ОписаниеОшибки - Строка - содержит описание ошибки, в случае если письмо отправить не удалось.
//   * СсылкаНаПисьмо - Неопределено - электронное исходящие письмо не было создано.
//                    - ДокументСсылка.ЭлектронноеПисьмоИсходящее - ссылка на созданное электронное исходящие письмо.
//
Функция РезультатОтправкиПисьма() Экспорт
	
	РезультатОтправкиПисьма = Новый Структура;
	
	РезультатОтправкиПисьма.Вставить("Отправлено", Ложь);
	РезультатОтправкиПисьма.Вставить("ОписаниеОшибки", "");
	РезультатОтправкиПисьма.Вставить("СсылкаНаПисьмо", Неопределено);
	
	Возврат РезультатОтправкиПисьма;
	
КонецФункции

Функция ШаблонПоВладельцу(ВладелецШаблона) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ШаблоныСообщений.Ссылка КАК Ссылка
		|ИЗ
		|	Справочник.ШаблоныСообщений КАК ШаблоныСообщений
		|ГДЕ
		|	ШаблоныСообщений.ВладелецШаблона = &ВладелецШаблона";
	
	Запрос.УстановитьПараметр("ВладелецШаблона", ВладелецШаблона);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если НЕ РезультатЗапроса.Пустой() Тогда
		Возврат РезультатЗапроса.Выгрузить()[0].Ссылка;
	Иначе
		Возврат Справочники.ШаблоныСообщений.ПустаяСсылка();
	КонецЕсли;
	
КонецФункции

// Функция-конструктор параметров сообщения
// 
// Параметры:
//  ПараметрыШаблона - Структура
//                   - Неопределено
// 
// Возвращаемое значение:
//  Структура:
//    * Тема - Строка
//    * Текст - Строка
//    * Получатель - СписокЗначений
//    * Вложения - ТаблицаЗначений:
//      ** Представление - Строка
//      ** АдресВоВременномХранилище - Строка
//      ** Кодировка - Строка
//      ** Идентификатор - Строка
//   * СообщенияПользователю - ФиксированныйМассив
//   * ДополнительныеПараметры - Неопределено
//                             - Структура
//
Функция КонструкторСообщения(ПараметрыШаблона = Неопределено) Экспорт
	
	Сообщение = Новый Структура();
	Сообщение.Вставить("Тема",       "");
	Сообщение.Вставить("Текст",      "");
	Сообщение.Вставить("Получатель", Новый СписокЗначений);
	Сообщение.Вставить("ДополнительныеПараметры",
		?(ПараметрыШаблона <> Неопределено, ПараметрыШаблона, Новый Структура()));
	Сообщение.Вставить("СообщенияПользователю", Новый ФиксированныйМассив(Новый Массив()));
	
	ТипСтрока = Новый ОписаниеТипов("Строка");
	Вложения = Новый ТаблицаЗначений;
	Вложения.Колонки.Добавить("Представление",             ТипСтрока);
	Вложения.Колонки.Добавить("АдресВоВременномХранилище", ТипСтрока);
	Вложения.Колонки.Добавить("Кодировка",                 ТипСтрока);
	Вложения.Колонки.Добавить("Идентификатор",             ТипСтрока);
	
	Сообщение.Вставить("Вложения", Вложения);
	
	Если ПараметрыШаблона <> Неопределено Тогда
		ЗаполнитьЗначенияСвойств(Сообщение, ПараметрыШаблона,, "Вложения");
	
		Для Каждого Вложение Из ПараметрыШаблона.Вложения Цикл
			
			НовоеВложение = Вложения.Добавить();
			НовоеВложение.Представление             = Вложение.Ключ;
			НовоеВложение.АдресВоВременномХранилище = Вложение.Значение;
			
		КонецЦикла;
		
	КонецЕсли;
	
	Возврат Сообщение;
КонецФункции

// Возвращаемое значение:
//   см. КонструкторСведенийОШаблоне
//
Функция СведенияОШаблоне(ПараметрыШаблона) Экспорт
	
	СведенияОШаблоне = КонструкторСведенийОШаблоне();
	
	ИмяУзлаОбщихРеквизитов = ШаблоныСообщений.ИмяУзлаОбщихРеквизитов();
	
	Если ТипЗнч(СведенияОШаблоне.ОбщиеРеквизиты) = Тип("ДеревоЗначений") Тогда
		Для каждого ОбщийРеквизит Из ОбщиеРеквизиты(СведенияОШаблоне.ОбщиеРеквизиты).Строки Цикл
			Если Не СтрНачинаетсяС(ОбщийРеквизит.Имя, ИмяУзлаОбщихРеквизитов + ".") Тогда
				ОбщийРеквизит.Имя = ИмяУзлаОбщихРеквизитов + "." + ОбщийРеквизит.Имя;
			КонецЕсли;
		КонецЦикла;
	Иначе
		СведенияОШаблоне.ОбщиеРеквизиты = ДеревоРеквизитов();
		ОбщиеРеквизитыДерево = ОпределитьОбщиеРеквизиты();
		СведенияОШаблоне.ОбщиеРеквизиты = ОбщиеРеквизиты(ОбщиеРеквизитыДерево);
	КонецЕсли;
	
	ОпределитьСписокРеквизитовИВложений(СведенияОШаблоне, ПараметрыШаблона);
	
	СформироватьПолныеПредставления(СведенияОШаблоне.Реквизиты.Строки);
	СформироватьПолныеПредставления(СведенияОШаблоне.ОбщиеРеквизиты.Строки);
	
	Возврат СведенияОШаблоне;
	
КонецФункции

// Функция-конструктор сведений о шаблоне.
// 
// Возвращаемое значение:
//  Структура:
//    * Назначение - Строка
//    * Вложения - ТаблицаЗначений:
//       ** Имя - Строка
//       ** Идентификатор - Строка
//       ** Представление - Строка
//       ** МенеджерПечати - Строка
//       ** ПараметрыПечати - Структура
//       ** ТипФайла - Строка
//       ** Статус - Строка
//       ** Реквизит - Строка
//       ** ИмяПараметра - Строка
//   * ОбщиеРеквизиты - ДеревоЗначений:
//       ** Имя - Строка
//       ** Представление - Строка
//       ** Подсказка - Строка
//       ** Формат - Строка
//       ** Тип - ОписаниеТипов
//       ** ПроизвольныйПараметр - Булево
//   * Реквизиты - ДеревоЗначений:
//       ** Имя - Строка
//       ** Представление - Строка
//       ** Подсказка - Строка
//       ** Формат - Строка
//       ** Тип - ОписаниеТипов
//       ** ПроизвольныйПараметр - Булево
// 
Функция КонструкторСведенийОШаблоне()
	
	СведенияОШаблоне = Новый Структура();
	
	НастройкиШаблоновСообщений = ШаблоныСообщенийСлужебныйПовтИсп.ПриОпределенииНастроек();
	
	СведенияОШаблоне.Вставить("Реквизиты", ДеревоРеквизитов());
	СведенияОШаблоне.Вставить("ОбщиеРеквизиты", НастройкиШаблоновСообщений.ОбщиеРеквизиты);
	СведенияОШаблоне.Вставить("Вложения", ТаблицаВложений());
	СведенияОШаблоне.Вставить("Назначение", "");
	
	Возврат СведенияОШаблоне;
	
КонецФункции

Функция ИмяПараметраБезСтрокиФормата(Знач ПараметрШаблонаИзТекста) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Имя",   "");
	Результат.Вставить("Формат", "");
	
	ПозицияФорматТекст = СтрНайти(ПараметрШаблонаИзТекста, "{", НаправлениеПоиска.СКонца);
	Если ПозицияФорматТекст > 0 Тогда
		Результат.Имя = Лев(ПараметрШаблонаИзТекста, ПозицияФорматТекст - 1);
		Результат.Формат = Сред(ПараметрШаблонаИзТекста, ПозицияФорматТекст + 1, СтрДлина(ПараметрШаблонаИзТекста) - ПозицияФорматТекст - 1);
	Иначе
		Результат.Имя = ПараметрШаблонаИзТекста;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ОпределитьСписокРеквизитовИВложений(СведенияОШаблоне, ПараметрыШаблона)
	
	Если ЗначениеЗаполнено(ПараметрыШаблона.ПолноеИмяТипаНазначения) Тогда
		
		// Реквизиты
		МетаданныеОбъект = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПараметрыШаблона.ПолноеИмяТипаНазначения);
		РеквизитыОбъектаНазначения = РеквизитыОбъектаНазначения(СведенияОШаблоне.Реквизиты, ПараметрыШаблона.ПолноеИмяТипаНазначения, ПараметрыШаблона.Назначение);
		РазворачиватьСсылочныеРеквизиты = ПараметрыШаблона.РазворачиватьСсылочныеРеквизиты;
		
		Если МетаданныеОбъект <> Неопределено Тогда
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъект.ПолноеИмя());
			
			Префикс = МетаданныеОбъект.Имя + ".";
			
			Если ПустаяСтрока(ПараметрыШаблона.Макет) Тогда
				РеквизитыПоМетаданнымОбъекта(РеквизитыОбъектаНазначения, МетаданныеОбъект,,, Префикс);
			Иначе
				МакетСКД = МенеджерОбъекта.ПолучитьМакет(ПараметрыШаблона.Макет);
				РеквизитыПоСКД(РеквизитыОбъектаНазначения, МакетСКД, МетаданныеОбъект.Имя);
				РазворачиватьСсылочныеРеквизиты = Ложь;
			КонецЕсли;
			
			ОпределитьСписокПечатныхФорм(МетаданныеОбъект, СведенияОШаблоне);
			Представление = МетаданныеОбъект.Представление();
			СсылкаНаОбъект = РеквизитыОбъектаНазначения.Добавить();
			СсылкаНаОбъект.Представление = НСтр("ru = 'Ссылка на'") + " """ + Представление + """";
			СсылкаНаОбъект.Имя           = Префикс + "ВнешняяСсылкаНаОбъект";
			СсылкаНаОбъект.Тип  = Новый ОписаниеТипов("Строка");
			СсылкаНаОбъект.ПолноеПредставление = Представление + "." + НСтр("ru = 'Ссылка на'") + " """ + Представление + """";
			
		Иначе
			Префикс = ПараметрыШаблона.ПолноеИмяТипаНазначения + ".";
			Представление = ПараметрыШаблона.Назначение;
		КонецЕсли;
		
		ШаблоныСообщенийПереопределяемый.ПриПодготовкеШаблонаСообщения(РеквизитыОбъектаНазначения, СведенияОШаблоне.Вложения, ПараметрыШаблона.ПолноеИмяТипаНазначения, ПараметрыШаблона);
		
		Если МетаданныеОбъект <> Неопределено Тогда
			МенеджерОбъекта.ПриПодготовкеШаблонаСообщения(РеквизитыОбъектаНазначения, СведенияОШаблоне.Вложения, ПараметрыШаблона);
		КонецЕсли;
		
		Для каждого РеквизитОбъектаНазначения Из РеквизитыОбъектаНазначения Цикл
			Если Не СтрНачинаетсяС(РеквизитОбъектаНазначения.Имя, Префикс) Тогда
				РеквизитОбъектаНазначения.Имя = Префикс + РеквизитОбъектаНазначения.Имя;
			КонецЕсли;
			Если РазворачиватьСсылочныеРеквизиты Тогда
				Если РеквизитОбъектаНазначения.Тип.Типы().Количество() = 1 Тогда
					ТипОбъекта = Метаданные.НайтиПоТипу(РеквизитОбъектаНазначения.Тип.Типы()[0]);
					Если ТипОбъекта <> Неопределено И СтрНачинаетсяС(ТипОбъекта.ПолноеИмя(), "Справочник") Тогда
						РазвернутьРеквизит(РеквизитОбъектаНазначения.Имя, РеквизитыОбъектаНазначения);
					КонецЕсли;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
	КонецЕсли;
	
	Для каждого ПроизвольныйПараметр Из ПараметрыШаблона.Параметры Цикл
		
		Если ПроизвольныйПараметр.Значение.ОписаниеТипа.Типы().Количество() > 0 Тогда
			Тип = ПроизвольныйПараметр.Значение.ОписаниеТипа.Типы()[0];
			МетаданныеОбъект = Метаданные.НайтиПоТипу(Тип);
			Если МетаданныеОбъект <> Неопределено Тогда
				МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъект.ПолноеИмя());
				Если МенеджерОбъекта <> Неопределено Тогда
					РеквизитыОбъектаНазначения = РеквизитыОбъектаНазначения(СведенияОШаблоне.Реквизиты, ПроизвольныйПараметр.Ключ);
					РеквизитыОбъектаНазначения.Родитель.Представление = ПроизвольныйПараметр.Значение.Представление;
					РеквизитыОбъектаНазначения.Родитель.Тип = ПроизвольныйПараметр.Значение.ОписаниеТипа;
					РеквизитыОбъектаНазначения.Родитель.ПроизвольныйПараметр = Истина;
					РеквизитыПоМетаданнымОбъекта(РеквизитыОбъектаНазначения, МетаданныеОбъект,,, МетаданныеОбъект.Имя + ".");
				КонецЕсли;
				ОпределитьСписокПечатныхФорм(МетаданныеОбъект, СведенияОШаблоне, ПроизвольныйПараметр.Ключ);
			Иначе
				ПроизвольныеПредставление = НСтр("ru = 'Произвольные'");
				Префикс = "Произвольные";
				РеквизитыОбъектаНазначения = РеквизитыОбъектаНазначения(СведенияОШаблоне.Реквизиты, Префикс, ПроизвольныеПредставление);
				НовыйСтрока = РеквизитыОбъектаНазначения.Добавить();
				НовыйСтрока.Имя = Префикс + "." + ПроизвольныйПараметр.Ключ;
				НовыйСтрока.Представление = ПроизвольныйПараметр.Значение.Представление;
				НовыйСтрока.Тип = ПроизвольныйПараметр.Значение.ОписаниеТипа;
				НовыйСтрока.ПроизвольныйПараметр = Истина;
			КонецЕсли;
		Иначе
			ПроизвольныеПредставление = НСтр("ru = 'Произвольные'");
			Префикс = "Произвольные";
			РеквизитыОбъектаНазначения = РеквизитыОбъектаНазначения(СведенияОШаблоне.Реквизиты, Префикс, ПроизвольныеПредставление);
			НовыйСтрока = РеквизитыОбъектаНазначения.Добавить();
			НовыйСтрока.Имя = Префикс + "." + ПроизвольныйПараметр.Ключ;
			НовыйСтрока.Представление = ПроизвольныйПараметр.Значение.Представление;
			НовыйСтрока.Тип = ОбщегоНазначения.ОписаниеТипаСтрока(150);
			НовыйСтрока.ПроизвольныйПараметр = Истина;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ПреобразоватьТекстШаблона( Знач Текст, Знач СписокВсехПараметров, ВариантКонвертации) Экспорт
	
	Если ВариантКонвертации = "ПараметрыВПредставление" Тогда
		ИмяРеквизитаИсточника  = "Имя";
		ИмяРеквизитаПолучателя = "ПолноеПредставление";
	Иначе
		ИмяРеквизитаИсточника  = "ПолноеПредставление";
		ИмяРеквизитаПолучателя = "Имя";
	КонецЕсли;
	
	ПараметрыВШаблоне = ПараметрыТекстаСообщения(Текст);
	
	Для каждого ПараметрВШаблоне Из ПараметрыВШаблоне Цикл
		
		ОписаниеПараметра = ИмяПараметраБезСтрокиФормата(ПараметрВШаблоне.Ключ);
		
		НайденныеСтроки = СписокВсехПараметров.Строки.НайтиСтроки(Новый Структура(ИмяРеквизитаИсточника, ОписаниеПараметра.Имя), Истина);
		Если НайденныеСтроки.Количество() > 0 Тогда
			
			Если ПустаяСтрока(ОписаниеПараметра.Формат) Тогда
				ПараметрыВШаблоне[ПараметрВШаблоне.Ключ] = НайденныеСтроки[0][ИмяРеквизитаПолучателя];
			Иначе
				ПараметрыВШаблоне[ПараметрВШаблоне.Ключ] = НайденныеСтроки[0][ИмяРеквизитаПолучателя] + "{" + ОписаниеПараметра.Формат + "}";
				НайденныеСтроки[0].Формат = ОписаниеПараметра.Формат;
			КонецЕсли;
			
		КонецЕсли;
	КонецЦикла;
	
	Возврат ЗаменитьПараметрыВТексте(Текст, ПараметрыВШаблоне);
	
КонецФункции

Функция ЗаменитьПараметрыВТексте(Знач ЗаменяемыйТекст, НаборПараметров)
	
	Для Каждого ОписаниеПараметра Из НаборПараметров Цикл
		ЗаменяемыйТекст = СтрЗаменить(ЗаменяемыйТекст, "[" + ОписаниеПараметра.Ключ + "]", "[" + ОписаниеПараметра.Значение + "]");
	КонецЦикла;
	
	Возврат ЗаменяемыйТекст;
	
КонецФункции

Процедура СформироватьПолныеПредставления(РеквизитыОбъектаНазначения, Представление = "")
	
	Совпадения = Новый Соответствие;
	Для каждого РеквизитОбъектаНазначения Из РеквизитыОбъектаНазначения Цикл
		ПолноеПредставление = Представление + РеквизитОбъектаНазначения.Представление;
		Если РеквизитОбъектаНазначения.Строки.Количество() > 0 Тогда
			СформироватьПолныеПредставления(РеквизитОбъектаНазначения.Строки, ПолноеПредставление + ".");
		КонецЕсли;
		
		Если Совпадения[ПолноеПредставление] = Неопределено Тогда
			РеквизитОбъектаНазначения.ПолноеПредставление = ПолноеПредставление;
			Совпадения.Вставить(ПолноеПредставление, РеквизитОбъектаНазначения);
		Иначе
			Для ПорядковыйНомер = 1 По 100 Цикл
				ПолноеПредставление = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					"%1.%2 (%3)", Представление, РеквизитОбъектаНазначения.Представление, ПорядковыйНомер);
				Если Совпадения[ПолноеПредставление] = Неопределено Тогда
					РеквизитОбъектаНазначения.ПолноеПредставление = ПолноеПредставление;
					Совпадения.Вставить(ПолноеПредставление, РеквизитОбъектаНазначения);
					Прервать;
				КонецЕсли;
			КонецЦикла;
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ОбъектЯвляетсяПредметомШаблона(ПолноеИмяТипаНазначения) Экспорт
	
	Результат = ШаблоныСообщенийСлужебныйПовтИсп.ПриОпределенииНастроек().ПредметыШаблонов.Найти(ПолноеИмяТипаНазначения, "Имя");
	Возврат Результат <> Неопределено;
	
КонецФункции

Функция СформироватьСообщениеВнешнейОбработкой(ПараметрыШаблона, СведенияОШаблоне, ПараметрыОтправки)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		
		СформированноеСообщение = КонструкторСообщения(ПараметрыШаблона);
		ВнешнийОбъект = МодульДополнительныеОтчетыИОбработки.ОбъектВнешнейОбработки(ПараметрыШаблона.ВнешняяОбработка);
		ПараметрыШаблона = ВнешнийОбъект.ПараметрыШаблона();
		
		Значения = Новый Структура;
		Для каждого ПараметрШаблона Из ПараметрыШаблона Цикл
			ЭтоПроизвольныйПараметр = Истина;
			Для каждого ОписаниеТипа Из ПараметрШаблона.ОписаниеТипа.Типы() Цикл
				Если ОписаниеТипа = ТипЗнч(ПараметрыОтправки.Предмет) Тогда
					ОбъектМетаданных = ПараметрыОтправки.Предмет.Метаданные(); // ОбъектМетаданных
					Значения.Вставить(ОбъектМетаданных.Имя, ПараметрыОтправки.Предмет);
					ЭтоПроизвольныйПараметр = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			Если ЭтоПроизвольныйПараметр Тогда
				Значение = ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры[ПараметрШаблона.ИмяПараметра];
				Значения.Вставить(ПараметрШаблона.ИмяПараметра, Значение);
			КонецЕсли;
		КонецЦикла;
		
		Сообщение = ВнешнийОбъект.СформироватьСообщениеПоШаблону(Значения);
		
		Если ТипЗнч(Сообщение) = Тип("Структура") И ПараметрыОтправки.ДополнительныеПараметры.ВидСообщения = "СообщениеSMS" Тогда
			
			СформированноеСообщение.Текст = Сообщение.ТекстСообщенияSMS;
			
		ИначеЕсли ТипЗнч(Сообщение) = Тип("Структура") И Сообщение.Свойство("СтруктураВложений") Тогда
			
			СформированноеСообщение.Текст = Сообщение.ТекстПисьмаHTML;
			СформированноеСообщение.Тема  = Сообщение.ТемаПисьма;
			
			Для каждого Вложение Из Сообщение.СтруктураВложений Цикл
				НовоеВложение = СформированноеСообщение.Вложения.Добавить();
				НовоеВложение.АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(Вложение.Значение.ПолучитьДвоичныеДанные(), ПараметрыОтправки.УникальныйИдентификатор);
				НовоеВложение.Идентификатор = Вложение.Ключ;
				НовоеВложение.Представление = Вложение.Ключ;
			КонецЦикла;
			
		КонецЕсли;
		
		СтандартнаяОбработка = Ложь;
		Получатели = ВнешнийОбъект.СтруктураДанныхПолучатели(Значения, СтандартнаяОбработка);
		Если ТипЗнч(Получатели) = Тип("Массив") Тогда
			
			СформированноеСообщение.Получатель = Новый СписокЗначений;
			
			Для каждого Получатель Из Получатели Цикл
				СформированноеСообщение.Получатель.Добавить(Получатель.Адрес, Получатель.Представление);
			КонецЦикла;
			
		КонецЕсли;
		
		Возврат СформированноеСообщение;
		
	КонецЕсли;
	
КонецФункции

Функция СообщениеБезШаблона(ПараметрыОтправки)
	
	ПараметрыШаблона = ШаблоныСообщенийКлиентСервер.ОписаниеПараметровШаблона();
	Если ПараметрыОтправки.ДополнительныеПараметры.Свойство("ВидСообщения")
		И ПараметрыОтправки.ДополнительныеПараметры.ВидСообщения = "СообщениеSMS" Тогда
			ПараметрыШаблона.ТипШаблона = "SMS";
	КонецЕсли;
	
	Если ПараметрыОтправки.ДополнительныеПараметры.Свойство("РасширенныйСписокПолучателей") Тогда
		ПараметрыШаблона.РасширенныйСписокПолучателей = ПараметрыОтправки.ДополнительныеПараметры.РасширенныйСписокПолучателей;
	КонецЕсли;
	
	МенеджерОбъекта = Неопределено;
	Если ПараметрыОтправки.Свойство("Предмет") И ЗначениеЗаполнено(ПараметрыОтправки.Предмет) Тогда
	МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипЗнч(ПараметрыОтправки.Предмет));
	Если МетаданныеОбъекта <> Неопределено Тогда
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя());
		КонецЕсли;
	КонецЕсли;
	
	СформированноеСообщение = КонструкторСообщения(ПараметрыШаблона);
	ЗаполнитьПолучателейСообщения(ПараметрыОтправки, ПараметрыШаблона, СформированноеСообщение, МенеджерОбъекта);
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
		МодульУправлениеПечатью = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатью");
		Если ПараметрыШаблона.ТипШаблона = "Письмо" И ЗначениеЗаполнено(ПараметрыОтправки.ДополнительныеПараметры.ПечатныеФормы) Тогда
			ПечатныеФормы = ПараметрыОтправки.ДополнительныеПараметры.ПечатныеФормы;
			СписокОбъектов = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПараметрыОтправки.Предмет);
			НастройкиСохранения = ПараметрыОтправки.ДополнительныеПараметры.НастройкиСохранения;
			Файлы = МодульУправлениеПечатью.НапечататьВФайл(ПечатныеФормы, СписокОбъектов, НастройкиСохранения);
			Для Каждого Файл Из Файлы Цикл
				Вложение = СформированноеСообщение.Вложения.Добавить();
				Вложение.АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(Файл.ДвоичныеДанные, ПараметрыОтправки.УникальныйИдентификатор);
				Вложение.Представление = Файл.ИмяФайла;
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	СформированноеСообщение.СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
	
	Возврат СформированноеСообщение;
	
КонецФункции

Функция СформироватьСписокПолучателейСообщения(СписокПолучателей)
	
	СпискаПолучателейСКонтактом = (ТипЗнч(СписокПолучателей)= Тип("Массив"));
	
	Кому = Новый Массив;
	Для каждого Получатель Из СписокПолучателей Цикл
		ПолучательСообщения = Новый Структура();
		ПолучательСообщения.Вставить("Представление", Получатель.Представление);
		
		Если СпискаПолучателейСКонтактом Тогда
			ПолучательСообщения.Вставить("Адрес",   Получатель.Адрес);
			ПолучательСообщения.Вставить("Контакт", Получатель.ИсточникКонтактнойИнформации);
		Иначе
			ПолучательСообщения.Вставить("Адрес",   Получатель.Значение);
		КонецЕсли;
		
		Кому.Добавить(ПолучательСообщения);
	КонецЦикла;
	
	Возврат Кому;

КонецФункции

Функция КомментарийПоНаименованиюШаблона(НаименованиеШаблона)

	Возврат НСтр("ru = 'Создано и отправлено по шаблону'") + " - " + НаименованиеШаблона;

КонецФункции

// Настройки

Функция ОпределитьПредметыШаблонов() Экспорт
	ИмяМакетаШаблонаПоУмолчанию = "ДанныеШаблонаСообщений";
	
	ОснованияДляШаблоновСообщений = Новый ТаблицаЗначений;
	ОснованияДляШаблоновСообщений.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
	ОснованияДляШаблоновСообщений.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	ОснованияДляШаблоновСообщений.Колонки.Добавить("Макет", Новый ОписаниеТипов("Строка"));
	ОснованияДляШаблоновСообщений.Колонки.Добавить("ЗначенияПараметровСКД", Новый ОписаниеТипов("Структура"));
	
	ТипыПредметовШаблоновСообщений = Метаданные.ОпределяемыеТипы.ПредметШаблонаСообщения.Тип.Типы();
	Для каждого ТипПредметаШаблонаСообщения Из ТипыПредметовШаблоновСообщений Цикл
		Если ТипПредметаШаблонаСообщения <> Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных") Тогда
			
			МетаданныеОбъект = Метаданные.НайтиПоТипу(ТипПредметаШаблонаСообщения);
			
			Если МетаданныеОбъект = Неопределено Или Не ПравоДоступа("Чтение", МетаданныеОбъект) Тогда
				Продолжить;
			КонецЕсли;
			
			Назначение = ОснованияДляШаблоновСообщений.Добавить();
			Назначение.Имя           = МетаданныеОбъект.ПолноеИмя();
			Назначение.Представление = МетаданныеОбъект.Представление();
			
			Если МетаданныеОбъект.Макеты.Найти(ИмяМакетаШаблонаПоУмолчанию) <> Неопределено Тогда
				Назначение.Макет = ИмяМакетаШаблонаПоУмолчанию;
				
				// Параметры СКД
				МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(Назначение.Имя);
				МакетСКД = МенеджерОбъекта.ПолучитьМакет(ИмяМакетаШаблонаПоУмолчанию);
				АдресСхемы = ПоместитьВоВременноеХранилище(МакетСКД);
				КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
				КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
				ПараметрПериод  = Новый ПараметрКомпоновкиДанных("Период");
				
				Для Каждого ДоступныйПараметр Из КомпоновщикНастроек.Настройки.ПараметрыДанных.ДоступныеПараметры.Элементы Цикл
					ИмяПараметра = Строка(ДоступныйПараметр.Параметр);
					Если НЕ (ДоступныйПараметр.Параметр =  ПараметрПериод
								ИЛИ СтрСравнить(ИмяПараметра, МетаданныеОбъект.Имя) = 0) Тогда
									Назначение.ЗначенияПараметровСКД.Вставить(ИмяПараметра, NULL);
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			
		КонецЕсли;
	КонецЦикла;
	
	Возврат ОснованияДляШаблоновСообщений;
	
КонецФункции

Функция ВидыШаблонов() Экспорт
	ТипыШаблонов = Новый СписокЗначений;
	ТипыШаблонов.Добавить(ШаблоныСообщенийКлиентСервер.ИмяШаблонаЭлектронныхПисем(), НСтр("ru = 'Электронного письма'"));
	ТипыШаблонов.Добавить(ШаблоныСообщенийКлиентСервер.ИмяШаблонаSMS(), НСтр("ru = 'Сообщения SMS'"));
	Возврат ТипыШаблонов;
КонецФункции

Функция ПодготовитьЗапросДляПолученияСпискаШаблонов(ТипШаблона, Предмет = Неопределено, ВладелецШаблона = Неопределено, ВыводитьОбщиеШаблон = Истина) Экспорт
	
	Если ТипШаблона = "SMS" Тогда
		ПредназначенДляSMS = Истина;
		ПредназначенДляЭлектронныхПисем = Ложь;
	Иначе
		ПредназначенДляSMS = Ложь;
		ПредназначенДляЭлектронныхПисем = Истина;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	ШаблоныСообщений.Ссылка,
	|	ШаблоныСообщений.Представление,
	|	ШаблоныСообщений.Наименование КАК Имя,
	|	ШаблоныСообщений.ВнешняяОбработка КАК ВнешняяОбработка,
	|	ШаблоныСообщений.ШаблонПоВнешнейОбработке КАК ШаблонПоВнешнейОбработке,
	|	ВЫБОР
	|		КОГДА ШаблоныСообщений.ПредназначенДляЭлектронныхПисем
	|			ТОГДА ВЫБОР
	|					КОГДА ШаблоныСообщений.ТипТекстаПисьма = ЗНАЧЕНИЕ(Перечисление.СпособыРедактированияЭлектронныхПисем.HTML)
	|						ТОГДА ШаблоныСообщений.ТекстШаблонаПисьмаHTML
	|					ИНАЧЕ ШаблоныСообщений.ТекстШаблонаПисьма
	|				КОНЕЦ
	|		ИНАЧЕ ШаблоныСообщений.ТекстШаблонаSMS
	|	КОНЕЦ КАК ТекстШаблона,
	|	ШаблоныСообщений.ТипТекстаПисьма,
	|	ШаблоныСообщений.ТемаПисьма,
	|		ВЫБОР
	|			КОГДА КОЛИЧЕСТВО(ШаблоныСообщений.Параметры.ИмяПараметра) > 0
	|				ТОГДА ИСТИНА
	|			ИНАЧЕ ЛОЖЬ
	|		КОНЕЦ КАК ЕстьПроизвольныеПараметры
	|ИЗ
	|	Справочник.ШаблоныСообщений КАК ШаблоныСообщений
	|ГДЕ
	|	(ШаблоныСообщений.ТолькоДляАвтора = ЛОЖЬ ИЛИ ШаблоныСообщений.Автор = &Пользователь) И
	|	ШаблоныСообщений.ПредназначенДляSMS = &ПредназначенДляSMS
	|	И ШаблоныСообщений.ПредназначенДляЭлектронныхПисем = &ПредназначенДляЭлектронныхПисем
	|	И ШаблоныСообщений.Назначение <> ""Служебный""
	|	И &ОтборПоВладельцуШаблона
	|	И ШаблоныСообщений.ПометкаУдаления = ЛОЖЬ";
	
	Если ЗначениеЗаполнено(ВладелецШаблона) Тогда
		ОтборПоВладельцу = "ШаблоныСообщений.ВладелецШаблона = &ВладелецШаблона";
		Запрос.УстановитьПараметр("ВладелецШаблона", ВладелецШаблона);
	Иначе
		ОтборПоВладельцу = "ИСТИНА";
	КонецЕсли;
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "&ОтборПоВладельцуШаблона", ОтборПоВладельцу);
	
	Запрос.УстановитьПараметр("ПредназначенДляSMS", ПредназначенДляSMS);
	Запрос.УстановитьПараметр("ПредназначенДляЭлектронныхПисем", ПредназначенДляЭлектронныхПисем);
	Запрос.УстановитьПараметр("Пользователь", Пользователи.АвторизованныйПользователь());
	
	ОтборОбщиеШаблоны = ?(ВыводитьОбщиеШаблон, "ШаблоныСообщений.ПредназначенДляВводаНаОсновании = ЛОЖЬ", "");
	
	Если ЗначениеЗаполнено(Предмет) Тогда
		Запрос.Текст = Запрос.Текст + " И (ШаблоныСообщений.ПолноеИмяТипаПараметраВводаНаОсновании = &ПолноеИмяТипаПредмета "
		+ ?(ЗначениеЗаполнено(ОтборОбщиеШаблоны), " ИЛИ " + ОтборОбщиеШаблоны, "") + ")";
		Запрос.УстановитьПараметр("ПолноеИмяТипаПредмета", 
			?(ТипЗнч(Предмет) = Тип("Строка"), Предмет, Предмет.Метаданные().ПолноеИмя()));
	Иначе 
		Запрос.Текст = Запрос.Текст + ?(ЗначениеЗаполнено(ОтборОбщиеШаблоны), " И " + ОтборОбщиеШаблоны, "");
	КонецЕсли;
	
	Возврат Запрос;
	
КонецФункции

// Реквизиты объекта основания.
//
// Параметры:
//  Реквизиты - ДеревоЗначений:
//   * Имя - Строка
//   * Представление - Строка
//  ПолноеИмяТипаНазначения - Строка
//  Представление - Строка
// 
// Возвращаемое значение:
//  ДеревоЗначений:
//    * Имя - Строка
//    * Представление - Строка
//
Функция РеквизитыОбъектаНазначения(Реквизиты, ПолноеИмяТипаНазначения, Знач Представление = "")
	
	МетаданныеОбъект = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПолноеИмяТипаНазначения);
	Если МетаданныеОбъект <> Неопределено Тогда
		ИмяРодителя = МетаданныеОбъект.Имя;
		Представление = ?(ЗначениеЗаполнено(Представление), Представление, МетаданныеОбъект.Представление());
	Иначе
		ИмяРодителя = ПолноеИмяТипаНазначения;
		Представление = ?(ЗначениеЗаполнено(Представление), Представление, ПолноеИмяТипаНазначения);
	КонецЕсли;
	
	УзелРеквизитовОбъектаНазначения = Реквизиты.Строки.Найти(ИмяРодителя, "Имя");
	Если УзелРеквизитовОбъектаНазначения = Неопределено Тогда
		УзелРеквизитовОбъектаНазначения = Реквизиты.Строки.Добавить();
		УзелРеквизитовОбъектаНазначения.Имя = ИмяРодителя;
		УзелРеквизитовОбъектаНазначения.Представление = Представление;
		УзелРеквизитовОбъектаНазначения.ПолноеПредставление = Представление;
	КонецЕсли;
	
	Возврат УзелРеквизитовОбъектаНазначения.Строки;
	
КонецФункции

Процедура СкрываемыеСтандартныеРеквизиты(Массив)
	
	ДобавитьВМассивУникальноеЗначение(Массив, "ПометкаУдаления");
	ДобавитьВМассивУникальноеЗначение(Массив, "Проведен");
	ДобавитьВМассивУникальноеЗначение(Массив, "Ссылка");
	ДобавитьВМассивУникальноеЗначение(Массив, "Предопределенный");
	ДобавитьВМассивУникальноеЗначение(Массив, "ИмяПредопределенныхДанных");
	ДобавитьВМассивУникальноеЗначение(Массив, "ЭтоГруппа");
	ДобавитьВМассивУникальноеЗначение(Массив, "Родитель");
	ДобавитьВМассивУникальноеЗначение(Массив, "Владелец");
	
КонецПроцедуры

Процедура ДобавитьВМассивУникальноеЗначение(Массив, Значение)
	Если Массив.Найти(Значение) = Неопределено Тогда
		Массив.Добавить(ВРег(Значение));
	КонецЕсли;
КонецПроцедуры

// Печатные формы и вложения

Процедура ОпределитьСписокПечатныхФорм(МетаданныеОбъект, Знач ПараметрыШаблона, ИмяПараметра = "")
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
		МодульУправлениеПечатью = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатью");
		
		ИсточникиКомандПечати   = МодульУправлениеПечатью.ИсточникиКомандПечати();
		Если ИсточникиКомандПечати.Найти(МетаданныеОбъект) <> Неопределено Тогда
			
			КомандыПечатиОбъекта = МодульУправлениеПечатью.КомандыПечатиОбъектаДоступныеДляВложений(МетаданныеОбъект);
			ПроверкаНаДубли      = Новый Соответствие;
			
			Для каждого Вложение Из КомандыПечатиОбъекта Цикл
				Если НЕ Вложение.Отключена
					И СтрНайти(Вложение.Идентификатор, ",") = 0
					И НЕ ПустаяСтрока(Вложение.МенеджерПечати)
					И НЕ Вложение.СразуНаПринтер
					И НЕ Вложение.СкрытаФункциональнымиОпциями
					И ПроверкаНаДубли[Вложение.УникальныйИдентификатор] = Неопределено Тогда
						НоваяСтрока                 = ПараметрыШаблона.Вложения.Добавить();
						НоваяСтрока.Имя             = Вложение.Идентификатор;
						НоваяСтрока.Идентификатор   = Вложение.УникальныйИдентификатор;
						НоваяСтрока.Представление   = Вложение.Представление;
						НоваяСтрока.МенеджерПечати  = Вложение.МенеджерПечати;
						НоваяСтрока.ТипФайла        = "MXL";
						НоваяСтрока.Статус          = "ПечатнаяФорма";
						НоваяСтрока.ИмяПараметра    = ИмяПараметра;
						НоваяСтрока.ПараметрыПечати = Вложение.ДополнительныеПараметры;
						ПроверкаНаДубли.Вставить(Вложение.УникальныйИдентификатор, Истина);
				КонецЕсли;
			КонецЦикла;
			
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

// Записывает вложение электронного письма, расположенное во временном хранилище в файл.
//
// Параметры:
//   Владелец - СправочникСсылка.ШаблоныСообщений
//   Сведения - см. ШаблоныСообщений.СтрокаВложений
//   ИмяФайла - Строка
//   Размер - Число 
//   КоличествоПустыхИменВоВложениях - Число 
//
Функция ЗаписатьВложениеЭлектронногоПисьмаИзВременногоХранилища(Владелец, Сведения, ИмяФайла, Размер, КоличествоПустыхИменВоВложениях = 0) Экспорт
	
	АдресВоВременномХранилище = Сведения.Имя;
	Описание = Сведения.Идентификатор;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");
		
		ИмяФайлаДляРазбора = ИмяФайла;
		РасширениеБезТочки = ПолучитьРасширениеФайла(ИмяФайлаДляРазбора);
		ИмяБезРасширения = ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ИмяФайлаДляРазбора);
		Если ПустаяСтрока(ИмяБезРасширения) Тогда
			
			ИмяБезРасширения = НСтр("ru = 'Вложение без имени'") + ?(КоличествоПустыхИменВоВложениях = 0, ""," " + Строка(КоличествоПустыхИменВоВложениях + 1));
			КоличествоПустыхИменВоВложениях = КоличествоПустыхИменВоВложениях + 1;
			
		Иначе
			ИмяБезРасширения =  ?(РасширениеБезТочки = "", ИмяБезРасширения, Лев(ИмяБезРасширения, СтрДлина(ИмяБезРасширения) - СтрДлина(РасширениеБезТочки) - 1));
		КонецЕсли;
		
		ПараметрыФайла = МодульРаботаСФайлами.ПараметрыДобавленияФайла();
		ПараметрыФайла.ВладелецФайлов = Владелец;
		ПараметрыФайла.ИмяБезРасширения = ИмяБезРасширения;
		ПараметрыФайла.РасширениеБезТочки = РасширениеБезТочки;
		Возврат МодульРаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресВоВременномХранилище, "", Описание);
		
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Процедура - Добавить вложение печатную форму
//
// Параметры:
//  ПараметрыОтправки
//  СведенияОШаблоне
//  Вложения
//  ПараметрыШаблоны
//
Процедура ДобавитьВыбранныеПечатныеФормыВоВложения(ПараметрыОтправки, СведенияОШаблоне, Вложения, ПараметрыШаблона)
	
	Если СведенияОШаблоне.Вложения.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ФорматыСохранения = Новый Массив;
	Если ТипЗнч(ПараметрыШаблона.ФорматыВложений) = Тип("СписокЗначений") Тогда
		Для каждого ФорматВложения Из ПараметрыШаблона.ФорматыВложений Цикл
			ФорматыСохранения.Добавить(?(ТипЗнч(ФорматВложения.Значение) = Тип("ТипФайлаТабличногоДокумента"),
				ФорматВложения.Значение,
				ТипФайлаТабличногоДокумента[ФорматВложения.Значение]));
		КонецЦикла;
	Иначе
		ФорматыСохранения.Добавить(СтандартныеПодсистемыСервер.ТипФайлаТабличногоДокументаPDF());
	КонецЕсли;
	
	Для каждого ВложениеПечатнаяФорма Из СведенияОШаблоне.Вложения Цикл
		ИмяПараметраСПечатнойФормойВШаблоне = ПараметрыШаблона.ВыбранныеВложения[ВложениеПечатнаяФорма.Идентификатор];
		Если ВложениеПечатнаяФорма.Статус = "ПечатнаяФорма" И ИмяПараметраСПечатнойФормойВШаблоне <> Неопределено Тогда
			ИмяМенеджераПечати = ВложениеПечатнаяФорма.МенеджерПечати;
			ПараметрыПечати    = ВложениеПечатнаяФорма.ПараметрыПечати;
			МассивОбъектов     = Новый Массив;
			
			// Если в шаблоне сообщений определен дополнительный(произвольный) параметр, который имеет свои печатные формы,
			// то определяем предмет (объект) по имени параметра, на основании которого будут формироваться эти печатные формы.
			Предмет = ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры[ИмяПараметраСПечатнойФормойВШаблоне];
			Если Предмет = Неопределено Тогда
				МассивОбъектов.Добавить(ПараметрыОтправки.Предмет);
			Иначе
				МассивОбъектов.Добавить(Предмет);
			КонецЕсли;
			
			ИменаМакетов       = ?(ПустаяСтрока(ВложениеПечатнаяФорма.Имя), ВложениеПечатнаяФорма.Идентификатор, ВложениеПечатнаяФорма.Имя);
			
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
				МодульУправлениеПечатью = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатью");
				
				Попытка
					КомандаПечати = Новый Структура;
					КомандаПечати.Вставить("Идентификатор", ИменаМакетов);
					КомандаПечати.Вставить("МенеджерПечати", ИмяМенеджераПечати);
					КомандаПечати.Вставить("ДополнительныеПараметры", ПараметрыПечати);
					
					НастройкиСохранения = МодульУправлениеПечатью.НастройкиСохранения();
					НастройкиСохранения.ФорматыСохранения = ФорматыСохранения;
					НастройкиСохранения.УпаковатьВАрхив = ПараметрыШаблона.УпаковатьВАрхив;
					НастройкиСохранения.ПереводитьИменаФайловВТранслит = ПараметрыШаблона.ТранслитерироватьИменаФайлов;
					НастройкиСохранения.ПодписьИПечать = ПараметрыШаблона.ПодписьИПечать;
					
					КоллекцияПечатныхФорм = МодульУправлениеПечатью.НапечататьВФайл(КомандаПечати, МассивОбъектов, НастройкиСохранения);
					
				Исключение
					// Ошибка при создании внешний печатной формы. Создаем дальше письмо, без этой печатной формы.
					ИнформацияОбОшибке = ИнформацияОбОшибке();
					
					ЗаписьЖурналаРегистрации(
						ИмяСобытияЖурналаРегистрации(),
						УровеньЖурналаРегистрации.Ошибка,,, НСтр("ru = 'Ошибка при создании внешней печатной формы. По причине:'") + Символы.ПС
							+ ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
						
					ОбщегоНазначения.СообщитьПользователю(ИнформацияОбОшибке.Описание); // сообщения обрабатываются в СформироватьСообщение
					Продолжить;
				КонецПопытки;
				
				Для Каждого ПечатнаяФорма Из КоллекцияПечатныхФорм Цикл
					
					АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ПечатнаяФорма.ДвоичныеДанные, ПараметрыОтправки.УникальныйИдентификатор);
					Вложения.Вставить(ПечатнаяФорма.ИмяФайла, АдресВоВременномХранилище);
				КонецЦикла;
				
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Функция-конструктор таблицы вложений
// 
// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Имя - Строка
//   * Идентификатор- Строка
//   * Представление - Строка
//   * МенеджерПечати - Строка
//   * ПараметрыПечати - Структура
//   * ТипФайла - Строка
//   * Статус - Строка
//   * Реквизит- Строка
//   * ИмяПараметра - Строка
// 
Функция ТаблицаВложений()
	
	ТипСтрока = Новый ОписаниеТипов("Строка");
	Вложения = Новый ТаблицаЗначений;
	Вложения.Колонки.Добавить("Имя",             ТипСтрока);
	Вложения.Колонки.Добавить("Идентификатор",   ТипСтрока);
	Вложения.Колонки.Добавить("Представление",   ТипСтрока);
	Вложения.Колонки.Добавить("МенеджерПечати",  ТипСтрока);
	Вложения.Колонки.Добавить("ПараметрыПечати", Новый ОписаниеТипов("Структура"));
	Вложения.Колонки.Добавить("ТипФайла",        ТипСтрока);
	Вложения.Колонки.Добавить("Статус",          ТипСтрока);
	Вложения.Колонки.Добавить("Реквизит",        ТипСтрока);
	Вложения.Колонки.Добавить("ИмяПараметра",    ТипСтрока);
	
	Возврат Вложения;
	
КонецФункции

// Получает расширение для переданного имени файла.
//
// Параметры:
//  ИмяФайла  - Строка - имя файла, для которого необходимо получить расширение.
//
// Возвращаемое значение:
//   Строка   - расширение, полученное из переданного имени файла.
//
Функция ПолучитьРасширениеФайла(Знач ИмяФайла)
	
	РасширениеФайла = "";
	МассивСтрок = СтрРазделить(ИмяФайла, ".", Ложь);
	Если МассивСтрок.Количество() > 1 Тогда
		РасширениеФайла = МассивСтрок[МассивСтрок.Количество() - 1];
	КонецЕсли;
	
	Возврат РасширениеФайла;
	
КонецФункции

// Определение и заполнение параметров(реквизитов) в тексте сообщения
// 
// Параметры:
//  Шаблон - ДанныеФормыСтруктура:
//   * Отправитель - Строка
//   * ПечатныеФормыИВложения - ТаблицаЗначений:
//     ** Идентификатор - Строка 
//     ** Имя - Строка 
//   * Параметры - ТаблицаЗначений
//
// Возвращаемое значение:
//   см. ШаблоныСообщенийКлиентСервер.ОписаниеПараметровШаблона
//
Функция ПараметрыШаблона(Шаблон) Экспорт
	
	Результат = ШаблоныСообщенийКлиентСервер.ОписаниеПараметровШаблона();
	
	Если ТипЗнч(Шаблон) = Тип("ДанныеФормыСтруктура") Или ТипЗнч(Шаблон) = Тип("СправочникОбъект.ШаблоныСообщений") Тогда
		
		УстановитьПараметрыШаблона(Шаблон, Результат);
		
	ИначеЕсли ТипЗнч(Шаблон) = Тип("СправочникСсылка.ШаблоныСообщений") Тогда
		Запрос = Новый Запрос;
		Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
		|	ШаблоныСообщений.ПредназначенДляВводаНаОсновании,
		|	ШаблоныСообщений.ПолноеИмяТипаПараметраВводаНаОсновании,
		|	ШаблоныСообщений.Назначение,
		|	ШаблоныСообщений.Наименование,
		|	ШаблоныСообщений.ПредназначенДляЭлектронныхПисем,
		|	ШаблоныСообщений.ТипТекстаПисьма,
		|	ВЫБОР
		|		КОГДА ШаблоныСообщений.ПредназначенДляЭлектронныхПисем
		|			ТОГДА ВЫБОР
		|					КОГДА ШаблоныСообщений.ТипТекстаПисьма = ЗНАЧЕНИЕ(Перечисление.СпособыРедактированияЭлектронныхПисем.HTML)
		|						ТОГДА ШаблоныСообщений.ТекстШаблонаПисьмаHTML
		|					ИНАЧЕ ШаблоныСообщений.ТекстШаблонаПисьма
		|				КОНЕЦ
		|		ИНАЧЕ ШаблоныСообщений.ТекстШаблонаSMS
		|	КОНЕЦ КАК ТекстШаблона,
		|	ШаблоныСообщений.ТемаПисьма,
		|	ШаблоныСообщений.УпаковатьВАрхив,
		|	ШаблоныСообщений.ТранслитерироватьИменаФайлов,
		|	ШаблоныСообщений.ФорматВложений,
		|	ШаблоныСообщений.ПредназначенДляSMS,
		|	ШаблоныСообщений.ОтправлятьВТранслите,
		|	ШаблоныСообщений.ПодписьИПечать,
		|	ШаблоныСообщений.ШаблонПоВнешнейОбработке,
		|	ШаблоныСообщений.ДобавлятьПрисоединенныеФайлы,
		|	ШаблоныСообщений.ВнешняяОбработка,
		|	ШаблоныСообщений.Ссылка,
		|	ШаблоныСообщений.ВладелецШаблона
		|ИЗ
		|	Справочник.ШаблоныСообщений КАК ШаблоныСообщений
		|ГДЕ
		|	ШаблоныСообщений.Ссылка = &Шаблон
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ШаблоныСообщенийПечатныеФормыИВложения.Идентификатор,
		|	ШаблоныСообщенийПечатныеФормыИВложения.Имя
		|ИЗ
		|	Справочник.ШаблоныСообщений.ПечатныеФормыИВложения КАК ШаблоныСообщенийПечатныеФормыИВложения
		|ГДЕ
		|	ШаблоныСообщенийПечатныеФормыИВложения.Ссылка = &Шаблон
		|;
		|
		|////////////////////////////////////////////////////////////////////////////////
		|ВЫБРАТЬ
		|	ШаблоныСообщенийПараметры.ПредставлениеПараметра,
		|	ШаблоныСообщенийПараметры.ТипПараметра,
		|	ШаблоныСообщенийПараметры.ИмяПараметра
		|ИЗ
		|	Справочник.ШаблоныСообщений.Параметры КАК ШаблоныСообщенийПараметры
		|ГДЕ
		|	ШаблоныСообщенийПараметры.Ссылка = &Шаблон";
		
		Запрос.УстановитьПараметр("Шаблон", Шаблон);
		
		РезультатЗапроса = Запрос.ВыполнитьПакет();
		СведенияОШаблоне = РезультатЗапроса[0].Выгрузить();
		
		Если СведенияОШаблоне.Количество() > 0 Тогда
			
			СтрокаСведенийОШаблоне = СведенияОШаблоне[0];
			Для каждого ВыбраннаяПечатнаяФорма Из РезультатЗапроса[1].Выгрузить() Цикл
				Результат.ВыбранныеВложения.Вставить(ВыбраннаяПечатнаяФорма.Идентификатор, ВыбраннаяПечатнаяФорма.Имя);
			КонецЦикла;
			Результат.Текст                      = СтрокаСведенийОШаблоне.ТекстШаблона;
			Результат.ТипШаблона                 = ?(СтрокаСведенийОШаблоне.ПредназначенДляSMS, "SMS", "Письмо");
			
			Если СтрокаСведенийОШаблоне.ПредназначенДляВводаНаОсновании Тогда
				Результат.Назначение              = СтрокаСведенийОШаблоне.Назначение;
				Результат.ПолноеИмяТипаНазначения = СтрокаСведенийОШаблоне.ПолноеИмяТипаПараметраВводаНаОсновании;
			КонецЕсли;
			Результат.ФорматПисьма                = СтрокаСведенийОШаблоне.ТипТекстаПисьма;
			
			Если Результат.ТипШаблона = "SMS" Тогда
				Результат.ПеревестиВТранслит      = СтрокаСведенийОШаблоне.ОтправлятьВТранслите;
			Иначе
				Результат.Тема                    = СтрокаСведенийОШаблоне.ТемаПисьма;
				Результат.УпаковатьВАрхив         = СтрокаСведенийОШаблоне.УпаковатьВАрхив;
				Результат.ФорматПисьма            = СтрокаСведенийОШаблоне.ТипТекстаПисьма;
				Результат.ПодписьИПечать          = СтрокаСведенийОШаблоне.ПодписьИПечать;
			КонецЕсли;
			
			ЗаполнитьЗначенияСвойств(Результат, СтрокаСведенийОШаблоне);
			Результат.ФорматыВложений             = СтрокаСведенийОШаблоне.ФорматВложений.Получить();
			
			Для каждого СтрокаПараметр Из РезультатЗапроса[2].Выгрузить() Цикл
				
				ОписаниеТипаПараметра = ОбщегоНазначения.ОписаниеТипаСтрока(250);
				Если ТипЗнч(СтрокаПараметр.ТипПараметра) = Тип("ХранилищеЗначения") Тогда
					ТипПараметраЗначение = СтрокаПараметр.ТипПараметра.Получить();
					Если ТипЗнч(ТипПараметраЗначение) = Тип("ОписаниеТипов") Тогда
						ОписаниеТипаПараметра = ТипПараметраЗначение;
					КонецЕсли;
				КонецЕсли;
				
				Результат.Параметры.Вставить(СтрокаПараметр.ИмяПараметра,
					Новый Структура("ОписаниеТипа, Представление", ОписаниеТипаПараметра, СтрокаПараметр.ПредставлениеПараметра));
				
			КонецЦикла;
			
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.ПолноеИмяТипаНазначения) 
		И НЕ ОбъектЯвляетсяПредметомШаблона(Результат.ПолноеИмяТипаНазначения) Тогда
		// Объект не входит в список предметов шаблона, поэтому шаблон может быть только общим.
		Результат.ПолноеИмяТипаНазначения = "";
		Результат.Назначение              = "";
	КонецЕсли;
	
	НастройкиШаблоновСообщений = ШаблоныСообщенийСлужебныйПовтИсп.ПриОпределенииНастроек();
	Результат.Вставить("РасширенныйСписокПолучателей", НастройкиШаблоновСообщений.РасширенныйСписокПолучателей);
	СведенияОПредмете = НастройкиШаблоновСообщений.ПредметыШаблонов.Найти(Результат.ПолноеИмяТипаНазначения, "Имя");
	Если СведенияОПредмете <> Неопределено Тогда
		Результат.Макет = СведенияОПредмете.Макет;
		Результат.ПараметрыСКД = СведенияОПредмете.ЗначенияПараметровСКД;
		Результат.Назначение   = СведенияОПредмете.Представление;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Шаблон - СправочникОбъект.ШаблоныСообщений
//         - ДанныеФормыСтруктура:
//   * Отправитель - Строка
//   * ПечатныеФормыИВложения - ТаблицаЗначений:
//     ** Идентификатор - Строка
//     ** Имя - Строка
//   * Параметры - ТаблицаЗначений
//  Результат - Структура:
//   * Тема - Строка
//   * Текст - Строка
//   * ПодписьИПечать - Булево
//   * ПараметрыСообщения - Структура
//   * Наименование - Строка
//   * Ссылка - Неопределено
//   * ВладелецШаблона - Неопределено
//   * ПараметрыСКД - Соответствие
//   * Параметры - Соответствие
//   * Макет - Строка
//   * ВыбранныеВложения - Соответствие
//   * ФорматыВложений - СписокЗначений
//   * РазворачиватьСсылочныеРеквизиты - Булево
//   * ШаблонПоВнешнейОбработке - Булево
//   * ВнешняяОбработка - Неопределено
//   * Отправитель - Строка
//   * ПеревестиВТранслит - Булево
//   * УпаковатьВАрхив - Булево
//   * ФорматПисьма - ПеречислениеСсылка.СпособыРедактированияЭлектронныхПисем
//   * ПолноеИмяТипаНазначения - Строка
//   * Назначение - Строка
//   * ТипШаблона - Строка
//
Процедура УстановитьПараметрыШаблона(Шаблон, Результат)
	Перем ПечатныеФормыИВложения;
	Результат.ТипШаблона                  = ?(Шаблон.ПредназначенДляSMS, "SMS", "Письмо");
	Результат.Тема                        = Шаблон.ТемаПисьма;
	
	Если Шаблон.ПредназначенДляВводаНаОсновании Тогда
		Результат.ПолноеИмяТипаНазначения  = Шаблон.ПолноеИмяТипаПараметраВводаНаОсновании;
		Результат.Назначение               = Шаблон.Назначение;
	КонецЕсли;
	Результат.ФорматПисьма                 = Шаблон.ТипТекстаПисьма;
	Результат.УпаковатьВАрхив              = Шаблон.УпаковатьВАрхив;
	Результат.ПеревестиВТранслит           = Шаблон.ОтправлятьВТранслите;
	Результат.Отправитель                  = Шаблон.Отправитель;
	Если Результат.ТипШаблона = "SMS" Тогда
		Результат.Текст                    = Шаблон.ТекстШаблонаSMS;
	ИначеЕсли Шаблон.ТипТекстаПисьма = Перечисления.СпособыРедактированияЭлектронныхПисем.HTML Тогда
		Результат.Текст                    = Шаблон.ТекстШаблонаПисьмаHTML;
	Иначе
		Результат.Текст                    = Шаблон.ТекстШаблонаПисьма;
	КонецЕсли;
	Результат.ТранслитерироватьИменаФайлов = Шаблон.ТранслитерироватьИменаФайлов;
	Результат.ПодписьИПечать               = Шаблон.ПодписьИПечать;
	
	ЗаполнитьЗначенияСвойств(Результат, Шаблон,, "Параметры");
	
	Для каждого ПечатныеФормыИВложения Из Шаблон.ПечатныеФормыИВложения Цикл
		
		Результат.ВыбранныеВложения.Вставить(ПечатныеФормыИВложения.Идентификатор, ПечатныеФормыИВложения.Имя);
	КонецЦикла;
	
	Для каждого СтрокаПараметр Из Шаблон.Параметры Цикл
		Результат.Параметры.Вставить(СтрокаПараметр.ИмяПараметра, Новый Структура("ОписаниеТипа, Представление", СтрокаПараметр.ОписаниеТипа, СтрокаПараметр.ПредставлениеПараметра));
	КонецЦикла;
	
КонецПроцедуры

// Возвращает соответствие параметров текста сообщения шаблона.
//
// Параметры:
//  ПараметрыШаблона - Структура - сведения о шаблоне.
//
// Возвращаемое значение:
//  Соответствие - соответствие имеющихся в тексте сообщения параметров.
//
Функция ПараметрыИзТекстаСообщения(ПараметрыШаблона) Экспорт
	
	Если ПараметрыШаблона.ТипШаблона = "Письмо" Тогда
		Возврат ОпределитьПараметрыТекстаСообщения(ПараметрыШаблона.Текст + " " + ПараметрыШаблона.Тема);
	ИначеЕсли ПараметрыШаблона.ТипШаблона = "SMS" Тогда
		Возврат ОпределитьПараметрыТекстаСообщения(ПараметрыШаблона.Текст);
	Иначе
		Возврат Новый Соответствие;
	КонецЕсли;
	
КонецФункции

Функция ОпределитьПараметрыТекстаСообщения(ТекстСообщения)
	
	МассивПараметров = Новый Соответствие;
	
	ДлинаСообщения = СтрДлина(ТекстСообщения);
	
	Текст = ТекстСообщения;
	Позиция = СтрНайти(Текст, "[");
	Пока Позиция > 0 Цикл
		Если Позиция + 1 > ДлинаСообщения Тогда
			Прервать;
		КонецЕсли;
		ПозицияОкончание = СтрНайти(Текст, "]", НаправлениеПоиска.СНачала, Позиция + 1);
		Если ПозицияОкончание > 0 Тогда
			НайденныйПараметр = Сред(Текст, Позиция + 1, ПозицияОкончание - Позиция - 1);
			МассивПараметров.Вставить(НайденныйПараметр, "");
		ИначеЕсли ПозицияОкончание = 0 Тогда
			ПозицияОкончание = Позиция + 1;
		КонецЕсли;
		Если ПозицияОкончание > ДлинаСообщения Тогда
			Прервать;
		КонецЕсли;
		Позиция = СтрНайти(Текст, "[", НаправлениеПоиска.СНачала, ПозицияОкончание);
	КонецЦикла;
	
	СоответствиеПараметров = Новый Соответствие;
	Для каждого ЭлементаМассиваПараметров Из МассивПараметров Цикл
		ПозицияФормат = СтрНайти(ЭлементаМассиваПараметров.Ключ, "{");
		Если ПозицияФормат > 0 Тогда
			ИмяПараметра  = Лев(ЭлементаМассиваПараметров.Ключ, ПозицияФормат - 1);
			СтрокаФормата = Сред(ЭлементаМассиваПараметров.Ключ, ПозицияФормат );
		Иначе
			ИмяПараметра  = ЭлементаМассиваПараметров.Ключ;
			СтрокаФормата = "";
		КонецЕсли;
		МассивРазобранныйПараметр = СтрРазделить(ИмяПараметра, ".", Ложь);
		Если МассивРазобранныйПараметр.Количество() < 2 Тогда
			Продолжить;
		КонецЕсли;
		
		УстановитьЭлементСоответствия(СоответствиеПараметров, МассивРазобранныйПараметр, СтрокаФормата);
	КонецЦикла;
	
	Возврат СоответствиеПараметров;
	
КонецФункции

Функция ПараметрыТекстаСообщения(ТекстСообщения) Экспорт
	
	МассивПараметров = Новый Соответствие;
	
	Набор = СтрРазделить(ТекстСообщения, "[");
	Для каждого ПараметрНабора Из Набор Цикл
		Позиция = СтрНайти(ПараметрНабора, "]");
		Если Позиция > 0 Тогда
			ИмяПараметра = Лев(ПараметрНабора, Позиция - 1);
			МассивПараметров.Вставить(ИмяПараметра, ИмяПараметра);
		КонецЕсли;
	КонецЦикла;
	
	Возврат МассивПараметров;
	
КонецФункции

Процедура УстановитьЭлементСоответствия(СоответствиеПараметров, Знач МассивРазобранныйПараметр, СтрокаФормата)
	ЭлементСоответствия = СоответствиеПараметров.Получить(МассивРазобранныйПараметр[0]);
	Если ЭлементСоответствия = Неопределено Тогда
		Если МассивРазобранныйПараметр.Количество() > 1 Тогда
			ВнутреннийЭлементСоответствия = Новый Соответствие;
			СоответствиеПараметров.Вставить(МассивРазобранныйПараметр[0], ВнутреннийЭлементСоответствия);
			МассивРазобранныйПараметр.Удалить(0);
			УстановитьЭлементСоответствия(ВнутреннийЭлементСоответствия, МассивРазобранныйПараметр, СтрокаФормата)
		Иначе
			Если СоответствиеПараметров[МассивРазобранныйПараметр[0] + СтрокаФормата] = Неопределено Тогда
				СоответствиеПараметров.Вставить(МассивРазобранныйПараметр[0] + СтрокаФормата, "");
			КонецЕсли;
		КонецЕсли;
	Иначе
		Если МассивРазобранныйПараметр.Количество() > 1 Тогда
			МассивРазобранныйПараметр.Удалить(0);
			УстановитьЭлементСоответствия(ЭлементСоответствия, МассивРазобранныйПараметр, СтрокаФормата)
		Иначе
			Если СоответствиеПараметров[МассивРазобранныйПараметр[0] + СтрокаФормата] = Неопределено Тогда
				СоответствиеПараметров.Вставить(МассивРазобранныйПараметр[0] + СтрокаФормата, "");
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
КонецПроцедуры

Функция СписокПараметров(ПараметрыТекстаСообщения, Префикс = "")
	
	СписокРеквизитов = "";
	Реквизиты = Новый Соответствие;
	Для каждого Реквизит Из ПараметрыТекстаСообщения Цикл
		Если ТипЗнч(Реквизит.Значение) = Тип("Соответствие") Тогда
			СписокРеквизитов = СписокРеквизитов + СписокПараметров(Реквизит.Значение, Реквизит.Ключ + ".");
		Иначе
			Если ПустаяСтрока(Реквизит.Значение) Тогда
				
				ОписаниеРеквизита = ИмяПараметраБезСтрокиФормата(Реквизит.Ключ);
				Если Реквизиты[ОписаниеРеквизита.Имя] <> Неопределено Тогда
					Продолжить;
				КонецЕсли;
				Реквизиты.Вставить(ОписаниеРеквизита.Имя, Истина);
				
				СписокРеквизитов = СписокРеквизитов + ", " + Префикс + ОписаниеРеквизита.Имя;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат СписокРеквизитов;
	
КонецФункции

Функция ЗаполнитьПараметрыСообщения(ПараметрыШаблона, ПараметрыТекстаСообщения, ПараметрыОтправки)
	
	Предмет = ПараметрыОтправки.Предмет;
	Сообщение = Новый Структура("ЗначенияРеквизитов, ЗначенияОбщихРеквизитов, Вложения, ДополнительныеПараметры");
	Сообщение.Вложения = Новый Соответствие;
	Сообщение.ЗначенияОбщихРеквизитов = Новый Соответствие;
	Сообщение.ЗначенияРеквизитов = Новый Соответствие;
	ИмяОбъекта = "";
	
	Если Предмет <> Неопределено 
		И ЗначениеЗаполнено(ПараметрыШаблона.ПолноеИмяТипаНазначения) Тогда
		ПредметМетаданные = Предмет.Метаданные(); // ОбъектМетаданных
		ИмяОбъекта = ПредметМетаданные.Имя;
		
		Если ПараметрыТекстаСообщения[ИмяОбъекта] <> Неопределено Тогда
			
			ЗаполнитьЗначенияРеквизитовПоПараметрам(Сообщение, ПараметрыТекстаСообщения[ИмяОбъекта], ПараметрыШаблона, Предмет);
			
		Иначе
			Сообщение.ЗначенияРеквизитов = ?(ПараметрыТекстаСообщения[ПараметрыШаблона.ПолноеИмяТипаНазначения] <> Неопределено,
				ПараметрыТекстаСообщения[ПараметрыШаблона.ПолноеИмяТипаНазначения], Новый Соответствие);
		КонецЕсли;
		
	КонецЕсли;
	
	Если ПараметрыОтправки.ДополнительныеПараметры.Свойство("ПроизвольныеПараметры") Тогда
		Для каждого ПроизвольныйПараметрШаблона Из ПараметрыТекстаСообщения Цикл
			
			КлючПараметра = ПроизвольныйПараметрШаблона.Ключ;
			Если СтрСравнить(КлючПараметра, ИмяОбъекта) = 0 Тогда
				Продолжить;
			КонецЕсли;
			
			Если КлючПараметра = ШаблоныСообщенийКлиентСервер.ЗаголовокПроизвольныхПараметров() Тогда
				ПроизвольныеРеквизиты = ПараметрыТекстаСообщения[ШаблоныСообщенийКлиентСервер.ЗаголовокПроизвольныхПараметров()];
				Если ТипЗнч(ПроизвольныеРеквизиты ) = Тип("Соответствие") Тогда
					Для Каждого ПроизвольныйРеквизит Из ПроизвольныеРеквизиты Цикл
						ОписаниеПараметра = ИмяПараметраБезСтрокиФормата(ПроизвольныйРеквизит.Ключ);
						Если ПустаяСтрока(ОписаниеПараметра.Формат) Тогда
							ПроизвольныеРеквизиты[ПроизвольныйРеквизит.Ключ] = ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры[ПроизвольныйРеквизит.Ключ];
						Иначе
							ПроизвольныеРеквизиты[ПроизвольныйРеквизит.Ключ] = 
								Формат(ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры[ОписаниеПараметра.Имя], ОписаниеПараметра.Формат);
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;
				Продолжить;
			КонецЕсли;
			
			Если КлючПараметра = ШаблоныСообщений.ИмяУзлаОбщихРеквизитов() Тогда
				Продолжить;
			КонецЕсли;
			
			ЗначениеПроизвольногоПараметра = ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры[КлючПараметра];
			Если ЗначениеПроизвольногоПараметра <> Неопределено Тогда
				
				Если НЕ ЗначениеЗаполнено(ЗначениеПроизвольногоПараметра) Тогда
					Продолжить;
				КонецЕсли;
				
				Если ТипЗнч(ЗначениеПроизвольногоПараметра) = Тип("Строка")
					Или ТипЗнч(ЗначениеПроизвольногоПараметра) = Тип("Дата") Тогда
					ПроизвольныеРеквизиты = ПараметрыТекстаСообщения[ШаблоныСообщенийКлиентСервер.ЗаголовокПроизвольныхПараметров()];
					Если ТипЗнч(ПроизвольныеРеквизиты ) = Тип("Соответствие") Тогда
						ПараметрыТекстаСообщения[ШаблоныСообщенийКлиентСервер.ЗаголовокПроизвольныхПараметров()][КлючПараметра] = ЗначениеПроизвольногоПараметра;
					КонецЕсли;
				Иначе
					
					ЗначениеПроизвольногоПараметраМетаданные = Метаданные.НайтиПоТипу(ТипЗнч(ЗначениеПроизвольногоПараметра)); // ОбъектМетаданных
					
					Если ЗначениеПроизвольногоПараметраМетаданные <> Неопределено Тогда
						ИмяОбъекта = ЗначениеПроизвольногоПараметраМетаданные.Имя;
						
						Если ПараметрыТекстаСообщения[ИмяОбъекта] <> Неопределено Тогда
							ЗаполнитьРеквизитыПоПредмету(ПараметрыТекстаСообщения[ИмяОбъекта], ЗначениеПроизвольногоПараметра);
							ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ПараметрыТекстаСообщения[ИмяОбъекта], ЗначениеПроизвольногоПараметра);
						КонецЕсли;
					КонецЕсли;
					
				КонецЕсли;
			Иначе
				
				ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры.Вставить(КлючПараметра, ПроизвольныйПараметрШаблона.Значение);
				
			КонецЕсли;
			
		КонецЦикла;
	КонецЕсли;
	
	Если ПараметрыТекстаСообщения[ШаблоныСообщений.ИмяУзлаОбщихРеквизитов()] <> Неопределено Тогда
		ЗаполнитьОбщиеРеквизиты(ПараметрыТекстаСообщения[ШаблоныСообщений.ИмяУзлаОбщихРеквизитов()]);
		Сообщение.ЗначенияОбщихРеквизитов = ПараметрыТекстаСообщения[ШаблоныСообщений.ИмяУзлаОбщихРеквизитов()];
	КонецЕсли;
	
	Возврат Сообщение;
	
КонецФункции

Процедура ЗаполнитьЗначенияРеквизитовПоПараметрам(Сообщение, Знач ПараметрыТекстаСообщения, Знач ПараметрыШаблона, Предмет)
	
	Если ПараметрыТекстаСообщения["ВнешняяСсылкаНаОбъект"] <> Неопределено Тогда
		ПараметрыТекстаСообщения["ВнешняяСсылкаНаОбъект"] = ВнешняяСсылкаНаОбъект(Предмет);
		Если ПараметрыТекстаСообщения.Количество() = 1 Тогда
			Возврат;
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПараметрыШаблона.Макет) Тогда
		ЗаполнитьРеквизитыПоСКД(ПараметрыТекстаСообщения, Предмет, ПараметрыШаблона);
	Иначе
		ЗаполнитьРеквизитыПоПредмету(ПараметрыТекстаСообщения, Предмет);
	КонецЕсли;
	ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ПараметрыТекстаСообщения, Предмет);
	Сообщение.ЗначенияРеквизитов = ПараметрыТекстаСообщения;

КонецПроцедуры

Функция УстановитьЗначенияРеквизитовВТекстСообщения(ПараметрыШаблона, ПараметрыТекстаСообщения, Предмет)
	
	Результат = Новый Структура("Тема, Текст, Вложения");
	
	Если ПараметрыШаблона.ТипШаблона = "Письмо" Тогда
		Результат.Тема = ВставитьПараметрыВСтрокуСогласноТаблицеПараметров(ПараметрыШаблона.Тема, ПараметрыТекстаСообщения);
	КонецЕсли;
	Результат.Текст = ВставитьПараметрыВСтрокуСогласноТаблицеПараметров(ПараметрыШаблона.Текст, ПараметрыТекстаСообщения);
	
	Возврат Результат;
	
КонецФункции

Процедура УстановитьПараметрыИзЗапроса(Параметры, Результат, Знач Префикс = "")
	
	Для каждого ЗначениеПараметра Из Параметры Цикл
		Если ТипЗнч(Параметры[ЗначениеПараметра.Ключ]) = Тип("Соответствие") Тогда
			УстановитьПараметрыИзЗапроса(Параметры[ЗначениеПараметра.Ключ], Результат, Префикс + ЗначениеПараметра.Ключ);
		Иначе
			Если ПустаяСтрока(ЗначениеПараметра.Значение) Тогда
				ПозицияФормата = СтрНайти(ЗначениеПараметра.Ключ, "{");
				Если ПозицияФормата > 0 Тогда
					ИмяПараметра = Лев(ЗначениеПараметра.Ключ, ПозицияФормата - 1);
					СтрокаФормата =Сред(ЗначениеПараметра.Ключ, ПозицияФормата + 1, СтрДлина(ЗначениеПараметра.Ключ) - СтрДлина(ИмяПараметра) -2);
					Значение = Результат.Получить(Префикс + ИмяПараметра);
					Если СтрНачинаетсяС(СтрокаФормата , "Д") Тогда
						Параметры[ЗначениеПараметра.Ключ] = Формат(ПреобразоватьСтрокиКТипу(Значение, "Дата"), СтрокаФормата);
					ИначеЕсли СтрНачинаетсяС(СтрокаФормата , "Ч") Тогда
						Параметры[ЗначениеПараметра.Ключ] = Формат(ПреобразоватьСтрокиКТипу(Значение, "Число"), СтрокаФормата);
					ИначеЕсли СтрНачинаетсяС(СтрокаФормата , "Б") Тогда
						Параметры[ЗначениеПараметра.Ключ] = Формат(ПреобразоватьСтрокиКТипу(Значение, "Булево"), СтрокаФормата);
					Иначе
						Параметры[ЗначениеПараметра.Ключ] = Формат(Результат.Получить(Префикс + ИмяПараметра), СтрокаФормата);
					КонецЕсли;
				Иначе
					Параметры[ЗначениеПараметра.Ключ] = ?(Результат[Префикс + ЗначениеПараметра.Ключ] <> Неопределено, Результат[Префикс + ЗначениеПараметра.Ключ], "");
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ПреобразоватьСтрокиКТипу(Значение, Тип)
	ОписаниеТипа = Новый ОписаниеТипов(Тип);
	Возврат ОписаниеТипа.ПривестиЗначение(Значение);
КонецФункции

Процедура ЗаполнитьОбщиеРеквизиты(ОбщиеРеквизиты) Экспорт
	
	Если ТипЗнч(ОбщиеРеквизиты) = Тип("Соответствие") Тогда
		Для каждого ОбщийРеквизит Из ОбщиеРеквизиты Цикл
			Если СтрНачинаетсяС(ОбщийРеквизит.Ключ, "ТекущаяДата") Тогда
				ОписаниеПараметра = ИмяПараметраБезСтрокиФормата(ОбщийРеквизит.Ключ);
				Если ПустаяСтрока(ОписаниеПараметра.Формат) Тогда
					ОбщиеРеквизиты[ОбщийРеквизит.Ключ] = ТекущаяДатаСеанса();
				Иначе
					ОбщиеРеквизиты[ОбщийРеквизит.Ключ] = Формат(ТекущаяДатаСеанса(), ОписаниеПараметра.Формат);
				КонецЕсли;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		
		Если ОбщиеРеквизиты.Получить("ЗаголовокСистемы") <> Неопределено Тогда
			ОбщиеРеквизиты["ЗаголовокСистемы"] = ИмяЭтойИнформационнойБазы();
		КонецЕсли;
		Если ОбщиеРеквизиты.Получить("АдресБазыВИнтернете") <> Неопределено Тогда
			ОбщиеРеквизиты["АдресБазыВИнтернете"] = ОбщегоНазначения.АдресПубликацииИнформационнойБазыВИнтернете();
		КонецЕсли;
		Если ОбщиеРеквизиты.Получить("АдресБазыВЛокальнойСети") <> Неопределено Тогда
			ОбщиеРеквизиты["АдресБазыВЛокальнойСети"] = ОбщегоНазначения.АдресПубликацииИнформационнойБазыВЛокальнойСети();
		КонецЕсли;
		
		Если ТипЗнч(ОбщиеРеквизиты.Получить("ТекущийПользователь")) = Тип("Соответствие") Тогда
			ТекущийПользователь = Пользователи.АвторизованныйПользователь();
			ЗаполнитьРеквизитыПоПредмету(ОбщиеРеквизиты.Получить("ТекущийПользователь"), ТекущийПользователь);
			ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ОбщиеРеквизиты.Получить("ТекущийПользователь"), ТекущийПользователь);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаполнитьРеквизитыПоСКД(Реквизиты, Предмет, ПараметрыШаблона) Экспорт
	
	ИмяМакета = ПараметрыШаблона.Макет;
	
	ПараметрыЗапроса = Новый Массив;
	МетаданныеОбъекта = Предмет.Метаданные();
	ИмяОбъекта = МетаданныеОбъекта.Имя;
	МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъекта.ПолноеИмя());
	МакетСКД = МенеджерОбъекта.ПолучитьМакет(ИмяМакета);
	
	АдресСхемы = ПоместитьВоВременноеХранилище(МакетСКД);
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
	ПараметрПериод = Новый ПараметрКомпоновкиДанных("Период");
	
	Для Каждого ДоступныйПараметр Из КомпоновщикНастроек.Настройки.ПараметрыДанных.ДоступныеПараметры.Элементы Цикл
		Если ДоступныйПараметр.Параметр <> ПараметрПериод Тогда
			ПараметрыЗапроса.Добавить(Строка(ДоступныйПараметр.Параметр));
		КонецЕсли;
	КонецЦикла;
	
	КомпоновщикНастроек.ЗагрузитьНастройки(МакетСКД.НастройкиПоУмолчанию);
	КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных();
	
	Для Каждого Реквизит Из Реквизиты Цикл
		ВыбранноеПоле = КомпоновщикНастроек.Настройки.Выбор.Элементы.Добавить(Тип("ВыбранноеПолеКомпоновкиДанных"));
		
		ИмяПоля = Реквизит.Ключ;
		Если СтрЗаканчиваетсяНа(ИмяПоля, "}") И СтрНайти(ИмяПоля, "{") > 0 Тогда
			ИмяПоля = Лев(ИмяПоля, СтрНайти(ИмяПоля, "{") - 1);
		КонецЕсли;
		
		ВыбранноеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяПоля);
	КонецЦикла;
	
	МакетКомпоновкиДанных = КомпоновщикМакета.Выполнить(МакетСКД, КомпоновщикНастроек.ПолучитьНастройки(),,, Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
	
	Если МакетКомпоновкиДанных.НаборыДанных.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	ТекстЗапросаМакет = МакетКомпоновкиДанных.НаборыДанных.Данные.Запрос;
	
	Запрос = Новый Запрос;
	Запрос.Текст = ТекстЗапросаМакет;
	
	НезаполненныеПараметры = Новый Массив;
	Для каждого ТребуемыйПараметр Из ПараметрыЗапроса Цикл
		Если СтрСравнить(ТребуемыйПараметр, "ТекущаяДата") = 0 Тогда
			Запрос.УстановитьПараметр(ТребуемыйПараметр, ТекущаяДатаСеанса());
		ИначеЕсли СтрСравнить(ТребуемыйПараметр, ИмяОбъекта) = 0 Тогда
			Запрос.УстановитьПараметр(ТребуемыйПараметр, Предмет);
		Иначе
			Если ПараметрыШаблона.ПараметрыСКД.Свойство(ТребуемыйПараметр) Тогда
				Запрос.УстановитьПараметр(ТребуемыйПараметр, ПараметрыШаблона.ПараметрыСКД[ТребуемыйПараметр]);
			Иначе
				НезаполненныеПараметры.Добавить(ТребуемыйПараметр);
			КонецЕсли;
			
		КонецЕсли;
	КонецЦикла;
	
	Если НезаполненныеПараметры.Количество() > 0 Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось сформировать сообщение, т.к. отсутствуют данные заполнения параметров: %1 для %2'"), 
			СтрСоединить(НезаполненныеПараметры, ","), Строка(Предмет));
	КонецЕсли;
	
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();
	Если РезультатЗапроса.Количество() > 0 Тогда
		РезультатЗапроса = СтрокаТаблицыЗначенийВСоответствие(РезультатЗапроса[0]);
		УстановитьПараметрыИзЗапроса(Реквизиты, РезультатЗапроса);
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаполнитьРеквизитыПоПредмету(Реквизиты, Предмет)
	
	МетаданныеОбъекта = Предмет.Метаданные();
	ПараметрыОснования = ОпределитьРеквизитыДляЗапросаПоМетаданным(Реквизиты, МетаданныеОбъекта);
	
	СписокРеквизитов = Сред(СписокПараметров(ПараметрыОснования), 3);
	Если ЗначениеЗаполнено(СписокРеквизитов) Тогда
		
		ЗначенияРеквизитов = Новый Соответствие;
		Для Каждого ЗначениеРеквизита Из ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Предмет, СписокРеквизитов, Истина) Цикл
			ЗначенияРеквизитов.Вставить(ЗначениеРеквизита.Ключ,ЗначениеРеквизита.Значение);
		КонецЦикла;
		УстановитьПараметрыИзЗапроса(Реквизиты, ЗначенияРеквизитов);
		
	КонецЕсли;
	
КонецПроцедуры

Функция СтрокаТаблицыЗначенийВСоответствие(СтрокаТаблицыЗначений)
	
	Соответствие = Новый Соответствие;
	Для каждого Колонка Из СтрокаТаблицыЗначений.Владелец().Колонки Цикл
		Соответствие.Вставить(Колонка.Имя, СтрокаТаблицыЗначений[Колонка.Имя]);
	КонецЦикла;
	
	Возврат Соответствие;
	
КонецФункции

// Подставляет в шаблон значения параметров сообщения и формирует текст сообщения.
//
// Параметры:
//  ШаблонСтроки        - Строка
//  ВставляемыеЗначения - Соответствие
//  Префикс             - Строка
// 
// Возвращаемое значение:
//   Строка
//
Функция ВставитьПараметрыВСтрокуСогласноТаблицеПараметров(Знач ШаблонСтроки, ВставляемыеЗначения, Знач Префикс = "") Экспорт
	
	Результат = ШаблонСтроки;
	Для каждого СписокРеквизитов Из ВставляемыеЗначения Цикл
		Если ТипЗнч(СписокРеквизитов.Значение) = Тип("Соответствие") Тогда
			Результат = ВставитьПараметрыВСтрокуСогласноТаблицеПараметров(Результат, СписокРеквизитов.Значение, Префикс + СписокРеквизитов.Ключ + ".");
		Иначе
			Результат = СтрЗаменить(Результат, "[" + Префикс + СписокРеквизитов.Ключ + "]", СписокРеквизитов.Значение);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Обрабатывает текст HTML для помещения в форматированный документ.
//
Процедура ОбработатьHTMLДляФорматированногоДокумента(ПараметрыШаблона, СформированноеСообщение, ПреобразовыватьHTMLДляФорматированногоДокумента, СписокФайлов = Неопределено) Экспорт

	Если ПустаяСтрока(СформированноеСообщение.Текст) Тогда
		Возврат;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");
		
		Если СписокФайлов = Неопределено Тогда
			СписокФайлов = Новый Массив;
			МодульРаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(ПараметрыШаблона.Шаблон, СписокФайлов);
		КонецЕсли;
		
		ДокументHTML = ПолучитьОбъектДокументHTMLИзТекстаHTML(СформированноеСообщение.Текст);
		Для каждого Картинка Из ДокументHTML.Картинки Цикл
			
			АтрибутИсточникКартинки = Картинка.Атрибуты.ПолучитьИменованныйЭлемент("src");
			
			ДополнительныеПараметры = Новый Структура;
			ДополнительныеПараметры.Вставить("ИдентификаторФормы", ПараметрыШаблона.УникальныйИдентификатор);
			ДополнительныеПараметры.Вставить("ВызыватьИсключение", Ложь);
			
			ИзображениеОтсутствуетВПрисоединенныхФайлах = Истина;
			
			Для Каждого ПрисоединенныйФайл Из СписокФайлов Цикл
				Если СтрЧислоВхождений(АтрибутИсточникКартинки.Значение, ПрисоединенныйФайл.ИДФайлаЭлектронногоПисьма) > 0 Тогда
					ДанныеФайла = МодульРаботаСФайлами.ДанныеФайла(ПрисоединенныйФайл.Ссылка, ДополнительныеПараметры);
					ОбработатьКартинкуВТекстеHTMLДляФорматированногоДокумента(Картинка, ДанныеФайла, СформированноеСообщение, 
					АтрибутИсточникКартинки, ПрисоединенныйФайл.Наименование, ПрисоединенныйФайл.ИДФайлаЭлектронногоПисьма);
					ИзображениеОтсутствуетВПрисоединенныхФайлах = Ложь;
					Прервать;
				ИначеЕсли СтрНачинаетсяС(АтрибутИсточникКартинки.Значение, "cid:" + ПрисоединенныйФайл.Наименование) Тогда
					НайденнаяСтрока = СформированноеСообщение.Вложения.Найти(ПрисоединенныйФайл.Наименование, "Представление");
					Если НайденнаяСтрока <> Неопределено Тогда
						СформированноеСообщение.Вложения.Удалить(НайденнаяСтрока);
					КонецЕсли;
					
					ДанныеФайла = МодульРаботаСФайлами.ДанныеФайла(ПрисоединенныйФайл.Ссылка, ДополнительныеПараметры);
					ОбработатьКартинкуВТекстеHTMLДляФорматированногоДокумента(Картинка, ДанныеФайла, СформированноеСообщение,
						АтрибутИсточникКартинки, ПрисоединенныйФайл.Наименование, ПрисоединенныйФайл.Наименование);
					ИзображениеОтсутствуетВПрисоединенныхФайлах = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			Если ИзображениеОтсутствуетВПрисоединенныхФайлах Тогда
				ИмяКартинки = Сред(АтрибутИсточникКартинки.Значение, 5);
				НайденнаяСтрока = СформированноеСообщение.Вложения.Найти(ИмяКартинки, "Представление");
				Если НайденнаяСтрока <> Неопределено Тогда
					ДвоичныеДанные = ПолучитьИзВременногоХранилища(НайденнаяСтрока.АдресВоВременномХранилище);
					АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные, ПараметрыШаблона.УникальныйИдентификатор);
					
					НайденнаяСтрока.Идентификатор = ИмяКартинки;
					НайденнаяСтрока.АдресВоВременномХранилище = АдресВоВременномХранилище;
					НовыйАтрибутКартинки = АтрибутИсточникКартинки.КлонироватьУзел(Ложь);
					НовыйАтрибутКартинки.ТекстовоеСодержимое = ИмяКартинки;
					Картинка.Атрибуты.УстановитьИменованныйЭлемент(НовыйАтрибутКартинки);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		Если ПреобразовыватьHTMLДляФорматированногоДокумента Тогда
			ТекстHTML = ПолучитьТекстHTMLИзОбъектаДокументHTML(ДокументHTML);
			СформированноеСообщение.Текст = ТекстHTML;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОбработатьКартинкуВТекстеHTMLДляФорматированногоДокумента(Картинка, ПрисоединенныйФайл, СформированноеСообщение, АтрибутИсточникКартинки, Представление, Идентификатор)
	
	НовыйАтрибутКартинки = АтрибутИсточникКартинки.КлонироватьУзел(Ложь);
	НовыйАтрибутКартинки.ТекстовоеСодержимое = ПрисоединенныйФайл.Наименование;
	Картинка.Атрибуты.УстановитьИменованныйЭлемент(НовыйАтрибутКартинки);
	
	НовоеВложение = СформированноеСообщение.Вложения.Добавить();
	НовоеВложение.Представление = Представление;
	НовоеВложение.АдресВоВременномХранилище = ПрисоединенныйФайл.СсылкаНаДвоичныеДанныеФайла;
	НовоеВложение.Идентификатор = Идентификатор;

КонецПроцедуры

// Получает текст HTML из объекта ДокументHTML.
//
// Параметры:
//  ДокументHTML  - ДокументHTML - документ, из которого будет извлекаться текст.
//
// Возвращаемое значение:
//   Строка   - текст HTML
//
Функция ПолучитьТекстHTMLИзОбъектаДокументHTML(ДокументHTML) Экспорт
	
	ЗаписьDOM = Новый ЗаписьDOM;
	ЗаписьHTML = Новый ЗаписьHTML;
	ЗаписьHTML.УстановитьСтроку();
	ЗаписьDOM.Записать(ДокументHTML, ЗаписьHTML);
	Возврат ЗаписьHTML.Закрыть();
	
КонецФункции

// Получает объект ДокументHTML из текста HTML.
//
// Параметры:
//  ТекстHTML  - Строка -  HTML текст.
//  Кодировка - Строка - кодировка текста
//
// Возвращаемое значение:
//   ДокументHTML   - созданный документ HTML.
//
Функция ПолучитьОбъектДокументHTMLИзТекстаHTML(ТекстHTML, Кодировка = Неопределено) Экспорт
	
	Построитель = Новый ПостроительDOM;
	ЧтениеHTML = Новый ЧтениеHTML;
	
	НовыйТекстHTML = ТекстHTML;
	ПозицияОткрытиеXML = СтрНайти(НовыйТекстHTML,"<?xml");
	
	Если ПозицияОткрытиеXML > 0 Тогда
		
		ПозицияЗакрытиеXML = СтрНайти(НовыйТекстHTML,"?>");
		Если ПозицияЗакрытиеXML > 0 Тогда
			
			НовыйТекстHTML = ЛЕВ(НовыйТекстHTML,ПозицияОткрытиеXML - 1) + ПРАВ(НовыйТекстHTML,СтрДлина(НовыйТекстHTML) - ПозицияЗакрытиеXML -1);
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если Кодировка = Неопределено Тогда
		ЧтениеHTML.УстановитьСтроку(ТекстHTML);
	Иначе
		ЧтениеHTML.УстановитьСтроку(ТекстHTML, Кодировка);
	КонецЕсли;
	Возврат Построитель.Прочитать(ЧтениеHTML);
	
КонецФункции

// Работа с реквизитами

Процедура РеквизитыПоСКД(Реквизиты, Макет, Знач Префикс = "") Экспорт
	
	Если ЗначениеЗаполнено(Префикс) Тогда
		Если НЕ СтрЗаканчиваетсяНа(Префикс, ".") Тогда
			Префикс = Префикс + ".";
		КонецЕсли;
	КонецЕсли;
	
	АдресСхемы = ПоместитьВоВременноеХранилище(Макет);
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы));
	
	Для Каждого ДоступноеПоле Из КомпоновщикНастроек.Настройки.ДоступныеПоляВыбора.Элементы Цикл
		
		Если ДоступноеПоле.Папка Тогда
			Продолжить;
		КонецЕсли;
		
		НовыйСтрока = ДобавитьРеквизит(Префикс + ДоступноеПоле.Поле, Реквизиты);
		НовыйСтрока.Представление = ДоступноеПоле.Заголовок;
		НовыйСтрока.Тип           = ДоступноеПоле.ТипЗначения;
		
	КонецЦикла;
	
КонецПроцедуры

// Описание
// 
// Параметры:
//  Реквизиты - КоллекцияСтрокДереваЗначений
//            - ДеревоЗначений:
//   * Имя - Строка
//   * Представление - Строка
//  МетаданныеОбъект - ОбъектМетаданных
//                   - Неопределено
//  СписокРеквизитов - Строка
//  ИсключаяРеквизиты - Строка
//  Префикс - Строка
//
Процедура РеквизитыПоМетаданнымОбъекта(Реквизиты, МетаданныеОбъект, СписокРеквизитов = "", ИсключаяРеквизиты = "", Префикс = "")
	
	СведенияОСпискеРеквизитов = Новый Структура("СписокРеквизитов, СписокСодержитДанные");
	СведенияОСпискеРеквизитов.СписокРеквизитов     = СтрРазделить(ВРег(СписокРеквизитов), ",", Ложь);
	СведенияОСпискеРеквизитов.СписокСодержитДанные = (СведенияОСпискеРеквизитов.СписокРеквизитов.Количество() > 0);
	
	СведенияОИсключаемыхРеквизитах = Новый Структура("СписокРеквизитов, СписокСодержитДанные");
	СведенияОИсключаемыхРеквизитах.СписокРеквизитов = СтрРазделить(ВРег(ИсключаяРеквизиты), ",", Ложь);
	СведенияОИсключаемыхРеквизитах.СписокСодержитДанные = (СведенияОИсключаемыхРеквизитах.СписокРеквизитов.Количество() > 0);
	
	Если ТипЗнч(МетаданныеОбъект) = Тип("ОбъектМетаданных") И НЕ ОбщегоНазначения.ЭтоПеречисление(МетаданныеОбъект) Тогда
		Для каждого Реквизит Из МетаданныеОбъект.Реквизиты Цикл
			Если НЕ СтрНачинаетсяС(Реквизит.Имя, "Удалить") Тогда
				Если Реквизит.Тип.Типы().Количество() = 1 И Реквизит.Тип.Типы()[0] = Тип("ХранилищеЗначения") Тогда
					Продолжить;
				КонецЕсли;
				
				ДобавитьРеквизитПоМетаданнымОбъекта(Реквизиты, Реквизит, Префикс, СведенияОСпискеРеквизитов, СведенияОИсключаемыхРеквизитах);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	СкрываемыеСтандартныеРеквизиты(СведенияОИсключаемыхРеквизитах.СписокРеквизитов);
	СведенияОИсключаемыхРеквизитах.СписокСодержитДанные = Истина;
	Для каждого Реквизит Из МетаданныеОбъект.СтандартныеРеквизиты Цикл
		ДобавитьРеквизитПоМетаданнымОбъекта(Реквизиты, Реквизит, Префикс, СведенияОСпискеРеквизитов, СведенияОИсключаемыхРеквизитах);
	КонецЦикла;
	
	Если НЕ ОбщегоНазначения.ЭтоПеречисление(МетаданныеОбъект) Тогда
		ДобавитьРеквизитыСвойств(МетаданныеОбъект, Префикс, Реквизиты, СведенияОИсключаемыхРеквизитах, СведенияОСпискеРеквизитов);
		ДобавитьРеквизитыКонтактнойИнформации(МетаданныеОбъект, Префикс, Реквизиты, СведенияОИсключаемыхРеквизитах, СведенияОСпискеРеквизитов);
	КонецЕсли;
	
КонецПроцедуры

Процедура ДобавитьРеквизитыКонтактнойИнформации(МетаданныеОбъект, Префикс, Реквизиты, СведенияОИсключаемыхРеквизитах, СведенияОСпискеРеквизитов)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		Ссылка = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъект.ПолноеИмя()).ПустаяСсылка();
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
		ВидыКонтактнойИнформацией = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(Ссылка);
		Если ВидыКонтактнойИнформацией.Количество() > 0 Тогда
			Для каждого ВидКонтактнойИнформацией Из ВидыКонтактнойИнформацией Цикл
				ДобавитьРеквизитПоМетаданнымОбъекта(Реквизиты, ВидКонтактнойИнформацией.Ссылка, Префикс, СведенияОСпискеРеквизитов, СведенияОИсключаемыхРеквизитах);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

Процедура ДобавитьРеквизитыСвойств(МетаданныеОбъект, Префикс, Реквизиты, СведенияОИсключаемыхРеквизитах, СведенияОСпискеРеквизитов)
	
	Свойства = Новый Массив;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
		ПустаяСсылка = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(МетаданныеОбъект.ПолноеИмя()).ПустаяСсылка();
		ПолучатьДопСведения = МодульУправлениеСвойствами.ИспользоватьДопСведения(ПустаяСсылка);
		ПолучатьДопРеквизиты = МодульУправлениеСвойствами.ИспользоватьДопРеквизиты(ПустаяСсылка);
		
		Если ПолучатьДопРеквизиты Или ПолучатьДопСведения Тогда
			Свойства = МодульУправлениеСвойствами.СвойстваОбъекта(ПустаяСсылка, ПолучатьДопРеквизиты, ПолучатьДопСведения);
			Для каждого Свойство Из Свойства Цикл
				ДобавитьРеквизитПоМетаданнымОбъекта(Реквизиты, Свойство, Префикс, СведенияОСпискеРеквизитов, СведенияОИсключаемыхРеквизитах);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Описание
// 
// Параметры:
//  Реквизиты - см. РеквизитыОбъектаНазначения
//  Реквизит - ОбъектМетаданных
//  Префикс - Строка
//  СведенияОСпискеРеквизитов - Структура:
//   * СписокРеквизитов - Массив
//   * СписокСодержитДанные - Булево
//  СведенияОИсключаемыхРеквизитах - Структура:
//   * СписокРеквизитов - Массив
//   * СписокСодержитДанные - Булево
//
Процедура ДобавитьРеквизитПоМетаданнымОбъекта(Реквизиты, Реквизит, Префикс, СведенияОСпискеРеквизитов, СведенияОИсключаемыхРеквизитах)
	
	ИмяРеквизита = Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		Если ТипЗнч(Реквизит) = Тип("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения") Тогда
			ЗначенияСвойство = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Реквизит, "ИдентификаторДляФормул, ТипЗначения, ФорматСвойства");
			ИмяРеквизита   = "~Свойство." + ЗначенияСвойство.ИдентификаторДляФормул;
			Представление = Строка(Реквизит);
			Тип           = ЗначенияСвойство.ТипЗначения;
			Формат        = ЗначенияСвойство.ФорматСвойства;
		КонецЕсли;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		Если ТипЗнч(Реквизит) = Тип("СправочникСсылка.ВидыКонтактнойИнформации") Тогда
			ИдентификаторДляФормул = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Реквизит, "ИдентификаторДляФормул");
			ИмяРеквизита  =  "~КИ." + ИдентификаторДляФормул;
			Представление = Строка(Реквизит);
			Тип           = Новый ОписаниеТипов("Строка");
			Формат        = "";
		КонецЕсли;
	КонецЕсли;
	
	Если ИмяРеквизита = Неопределено Тогда
		ИмяРеквизита  = Реквизит.Имя;
		Представление = Реквизит.Представление();
		Тип           = Реквизит.Тип;
		Формат        = Реквизит.Формат;
	КонецЕсли;
	
	Если СведенияОСпискеРеквизитов.СписокСодержитДанные
		И СведенияОСпискеРеквизитов.СписокРеквизитов.Найти(ВРег(СокрЛП(ИмяРеквизита))) = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Если СведенияОИсключаемыхРеквизитах.СписокСодержитДанные
		И СведенияОИсключаемыхРеквизитах.СписокРеквизитов.Найти(ВРег(СокрЛП(ИмяРеквизита))) <> Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	НовыйСтрока = Реквизиты.Добавить();
	НовыйСтрока.Имя           = Префикс + ИмяРеквизита;
	НовыйСтрока.Представление = Представление;
	НовыйСтрока.Тип           = Тип;
	НовыйСтрока.Формат        = Формат;
	
КонецПроцедуры

Функция ЗначенияРеквизитовСвойств(Предмет)
	
	ЗначенияСвойств = Новый ТаблицаЗначений;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
		ПолучатьДопСведения = МодульУправлениеСвойствами.ИспользоватьДопСведения(Предмет);
		ПолучатьДопРеквизиты = МодульУправлениеСвойствами.ИспользоватьДопРеквизиты(Предмет);
		
		Если ПолучатьДопРеквизиты Или ПолучатьДопСведения Тогда
			ЗначенияСвойств = МодульУправлениеСвойствами.ЗначенияСвойств(Предмет, ПолучатьДопРеквизиты, ПолучатьДопСведения);
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат ЗначенияСвойств;
	
КонецФункции

Функция ОпределитьРеквизитыДляЗапросаПоМетаданным(Знач ПараметрыТекстаСообщения, МетаданныеОбъекта)
	
	ПараметрыОснования = СкопироватьСоответствие(ПараметрыТекстаСообщения);
	ОбработатьОпределитьРеквизитыДляЗапросаПоМетаданным(ПараметрыОснования, МетаданныеОбъекта);
	Возврат ПараметрыОснования;
	
КонецФункции

Процедура ОбработатьОпределитьРеквизитыДляЗапросаПоМетаданным(ПараметрыОснования, МетаданныеОбъекта)
	
	КлючиУдаляемыхПараметров = Новый Массив;
	
	Для каждого ПараметрОснования Из ПараметрыОснования Цикл
		Позиция = СтрНайти(ПараметрОснования.Ключ, "{");
		Если Позиция > 0 Тогда
			ИмяПараметра = Лев(ПараметрОснования.Ключ, Позиция - 1);
		Иначе
			ИмяПараметра = ПараметрОснования.Ключ;
		КонецЕсли;
		Если ТипЗнч(ПараметрОснования.Значение) = Тип("Соответствие") Тогда
			МетаданныеОбъектаПоКлючу = МетаданныеОбъекта.Реквизиты.Найти(ИмяПараметра);
			Если МетаданныеОбъектаПоКлючу <> Неопределено Тогда
				Для каждого Тип Из МетаданныеОбъектаПоКлючу.Тип.Типы() Цикл
					ОбработатьОпределитьРеквизитыДляЗапросаПоМетаданным(ПараметрОснования.Значение, Метаданные.НайтиПоТипу(Тип));
				КонецЦикла;
			Иначе
				КлючиУдаляемыхПараметров.Добавить(ПараметрОснования.Ключ);
			КонецЕсли;
		ИначеЕсли МетаданныеОбъекта.Реквизиты.Найти(ИмяПараметра) = Неопределено Тогда
			РеквизитНеНайден = Истина;
				Для каждого СтандартныеРеквизиты Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл
				Если СтрСравнить(СтандартныеРеквизиты.Имя, ИмяПараметра) = 0 Тогда
					РеквизитНеНайден = Ложь;
					Прервать;
				КонецЕсли;
			КонецЦикла;
			
			Если РеквизитНеНайден Тогда
				КлючиУдаляемыхПараметров.Добавить(ПараметрОснования.Ключ);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Для каждого КлючПараметра Из КлючиУдаляемыхПараметров Цикл
		ПараметрыОснования.Удалить(КлючПараметра);
	КонецЦикла;
	
КонецПроцедуры

// Параметры:
//  ПараметрыТекстаСообщения - см. ШаблоныСообщенийСлужебный.ПараметрыИзТекстаСообщения
//  ОшибочныеРеквизиты - Массив
//  СведенияОШаблоне - см. ШаблоныСообщенийСлужебный.СведенияОШаблоне
//  Префикс - Строка
//
Процедура ОпределитьОшибочныеРеквизиты(ПараметрыТекстаСообщения, ОшибочныеРеквизиты, СведенияОШаблоне, Префикс = "")
	
	ИмяУзлаОбщихРеквизитов = ШаблоныСообщений.ИмяУзлаОбщихРеквизитов();
	Для каждого Реквизит Из ПараметрыТекстаСообщения Цикл
		Если ТипЗнч(Реквизит.Значение) = Тип("Соответствие") Тогда
			ОпределитьОшибочныеРеквизиты(Реквизит.Значение, ОшибочныеРеквизиты, СведенияОШаблоне, Префикс + Реквизит.Ключ + ".");
		Иначе
			ПозицияФорматТекст = СтрНайти(Реквизит.Ключ, "{", НаправлениеПоиска.СКонца);
			Если ПозицияФорматТекст > 0 Тогда 
				ИмяПараметра = Префикс + Лев(Реквизит.Ключ, ПозицияФорматТекст - 1);
			Иначе
				ИмяПараметра = Префикс + Реквизит.Ключ;
			КонецЕсли;
			Если СтрНачинаетсяС(Префикс, ИмяУзлаОбщихРеквизитов) Тогда
				НайденныйРеквизит = СведенияОШаблоне.ОбщиеРеквизиты.Строки.Найти(ИмяПараметра, "Имя", Истина);
			Иначе
				НайденныйРеквизит = СведенияОШаблоне.Реквизиты.Строки.Найти(ИмяПараметра, "Имя", Истина);
			КонецЕсли;
			Если НайденныйРеквизит = Неопределено Тогда 
				ОшибочныеРеквизиты.Добавить(ИмяПараметра);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ПараметрыТекстаСообщения, Предмет);
	
	МетаданныеОбъекта = Предмет.Метаданные();
	ЗначенияСвойств = ЗначенияРеквизитовСвойств(Предмет);
	КонтактнаяИнформацияОбъектов = ЗначенияРеквизитовКонтактнойИнформации(Предмет);
	
	Если ТипЗнч(ПараметрыТекстаСообщения) <> Тип("Соответствие") Тогда
		Возврат;
	КонецЕсли;
	
	Для каждого ПараметрОснования Из ПараметрыТекстаСообщения Цикл
		
		Если СтрНачинаетсяС(ПараметрОснования.Ключ, "~Свойство") Тогда
			
			Для каждого ПараметрСвойство Из ПараметрОснования.Значение Цикл
				Если ЗначенияСвойств <> Неопределено Тогда
					Для каждого СтрокаСвойство Из ЗначенияСвойств Цикл
						ОписаниеПараметра = ИмяПараметраБезСтрокиФормата(ПараметрСвойство.Ключ);
						ИдентификаторДляФормул = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СтрокаСвойство.Свойство, "ИдентификаторДляФормул");
						
						Если СтрСравнить(ИдентификаторДляФормул, ОписаниеПараметра.Имя) = 0 Тогда
							
							Если ТипЗнч(ПараметрОснования.Значение[ПараметрСвойство.Ключ]) = Тип("Соответствие")
								И (Справочники.ТипВсеСсылки().СодержитТип(ТипЗнч(СтрокаСвойство.Значение))
								Или ПланыВидовХарактеристик.ТипВсеСсылки().СодержитТип(ТипЗнч(СтрокаСвойство.Значение))) Тогда
								
								ЗаполнитьРеквизитыПоПредмету(ПараметрОснования.Значение[ПараметрСвойство.Ключ], СтрокаСвойство.Значение);
								ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ПараметрОснования.Значение[ПараметрСвойство.Ключ], СтрокаСвойство.Значение);
								
							ИначеЕсли ЗначениеЗаполнено(ОписаниеПараметра.Формат) Тогда
								ПараметрОснования.Значение[ПараметрСвойство.Ключ] = Формат(СтрокаСвойство.Значение, ОписаниеПараметра.Формат);
							Иначе
								ПараметрОснования.Значение[ПараметрСвойство.Ключ] = Строка(СтрокаСвойство.Значение);
							КонецЕсли;
							
						КонецЕсли;
						
					КонецЦикла;
				КонецЕсли;
			КонецЦикла;
			
		ИначеЕсли СтрНачинаетсяС(ПараметрОснования.Ключ, "~КИ") Тогда
			
			Для каждого ПараметрКонтактнойИнформации Из ПараметрОснования.Значение Цикл
				
				Для каждого КонтактнаяИнформацияОбъекта Из КонтактнаяИнформацияОбъектов Цикл
					ИдентификаторДляФормул = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(КонтактнаяИнформацияОбъекта.Вид, "ИдентификаторДляФормул");
					
					Если СтрСравнить(ИдентификаторДляФормул, ПараметрКонтактнойИнформации.Ключ) = 0 Тогда
						Если ЗначениеЗаполнено(ПараметрОснования.Значение[ПараметрКонтактнойИнформации.Ключ]) Тогда
							ПредыдущиеЗначение = ПараметрОснования.Значение[ПараметрКонтактнойИнформации.Ключ] +", ";
						Иначе
							ПредыдущиеЗначение = "";
						КонецЕсли;
						ПараметрОснования.Значение[ПараметрКонтактнойИнформации.Ключ] = ПредыдущиеЗначение + Строка(КонтактнаяИнформацияОбъекта.Представление);
					КонецЕсли;
				КонецЦикла;
				
			КонецЦикла;
			
		ИначеЕсли ТипЗнч(ПараметрОснования.Значение) = Тип("Соответствие") Тогда
			
			МетаданныеОбъектаПоКлючу = МетаданныеОбъекта.Реквизиты.Найти(ПараметрОснования.Ключ);
			Если МетаданныеОбъектаПоКлючу <> Неопределено  Тогда
				ЗаполнитьРеквизитыСвойствИКонтактнойИнформации(ПараметрОснования.Значение, Предмет[ПараметрОснования.Ключ]);
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЗначенияРеквизитовКонтактнойИнформации(Предмет)
	
	КонтактнаяИнформацияОбъектов = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");	
		
		ОбъектыСКонтактнойИнформацией = Новый Массив;
		ОбъектыСКонтактнойИнформацией.Добавить(Предмет);
		ВидыКонтактнойИнформации = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(Предмет.Ссылка);
		Если ВидыКонтактнойИнформации.Количество() > 0 Тогда
			КонтактнаяИнформацияОбъектов = МодульУправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъектов(ОбъектыСКонтактнойИнформацией,,, ТекущаяДатаСеанса());
		КонецЕсли;
	КонецЕсли;
	
	Возврат КонтактнаяИнформацияОбъектов;
	
КонецФункции

Функция ЗаголовокОбщиеРеквизиты() Экспорт
	Возврат НСтр("ru = 'Общие реквизиты'");
КонецФункции

// Работа с реквизитами вспомогательные методы 
// 
// Возвращаемое значение:
//  ДеревоЗначений:
//    * Имя - Строка
//    * Представление - Строка
//    * Подсказка - Строка
//    * Формат - Строка
//    * Тип - ОписаниеТипов
//    * ПроизвольныйПараметр - Булево
//
Функция ДеревоРеквизитов()
	
	ТипСтрока = Новый ОписаниеТипов("Строка");
	
	Реквизиты = Новый ДеревоЗначений;
	Реквизиты.Колонки.Добавить("Имя", ТипСтрока);
	Реквизиты.Колонки.Добавить("Представление", ТипСтрока);
	Реквизиты.Колонки.Добавить("Подсказка", ТипСтрока);
	Реквизиты.Колонки.Добавить("ПолноеПредставление", ОбщегоНазначения.ОписаниеТипаСтрока(300));
	Реквизиты.Колонки.Добавить("Формат", ТипСтрока);
	Реквизиты.Колонки.Добавить("Тип", Новый ОписаниеТипов("ОписаниеТипов"));
	Реквизиты.Колонки.Добавить("ПроизвольныйПараметр", Новый ОписаниеТипов("Булево"));
	
	Возврат Реквизиты;
	
КонецФункции

Функция ОбщиеРеквизиты(Реквизиты) Экспорт
	
	УзелРеквизитов = Реквизиты.Строки.Найти(ШаблоныСообщений.ИмяУзлаОбщихРеквизитов(), "Имя");
	Если УзелРеквизитов = Неопределено Тогда
		УзелРеквизитов = Реквизиты.Строки.Добавить();
		УзелРеквизитов.Имя = ШаблоныСообщений.ИмяУзлаОбщихРеквизитов();
		УзелРеквизитов.ПолноеПредставление = ЗаголовокОбщиеРеквизиты();
		УзелРеквизитов.Представление = ЗаголовокОбщиеРеквизиты();
	КонецЕсли;
	
	Возврат УзелРеквизитов;
	
КонецФункции

Функция ОпределитьОбщиеРеквизиты() Экспорт
	
	ОбщиеРеквизиты = ДеревоРеквизитов();
	ОбщиеРеквизитыСтроки = ОбщиеРеквизиты(ОбщиеРеквизиты);
	
	ДобавитьОбщийРеквизит(ОбщиеРеквизитыСтроки, "ТекущаяДата", НСтр("ru = 'Текущая дата'"), Новый ОписаниеТипов("Дата"));
	ДобавитьОбщийРеквизит(ОбщиеРеквизитыСтроки, "ЗаголовокСистемы", НСтр("ru = 'Заголовок системы'"));
	ДобавитьОбщийРеквизит(ОбщиеРеквизитыСтроки, "АдресБазыВИнтернете", НСтр("ru = 'Адрес базы в Интернете'"), Новый ОписаниеТипов("Строка"));
	ДобавитьОбщийРеквизит(ОбщиеРеквизитыСтроки, "АдресБазыВЛокальнойСети", НСтр("ru = 'Адрес базы в локальной сети'"), Новый ОписаниеТипов("Строка"));
	ДобавитьОбщийРеквизит(ОбщиеРеквизитыСтроки, "ТекущийПользователь", НСтр("ru = 'Текущий пользователь'"), Новый ОписаниеТипов("СправочникСсылка.Пользователи"));
	
	СписокИсключаемыхРеквизитов = "Недействителен,ИдентификаторПользователяИБ,ИдентификаторПользователяСервиса,Подготовлен,Служебный";
	
	Если Метаданные.ОпределяемыеТипы.ФизическоеЛицо.Тип.Типы().Количество() = 1
		И Метаданные.ОпределяемыеТипы.ФизическоеЛицо.Тип.Типы()[0] = Тип("Строка") Тогда
		СписокИсключаемыхРеквизитов = СписокИсключаемыхРеквизитов + ",ФизическоеЛицо";
	КонецЕсли;
	
	Если Метаданные.ОпределяемыеТипы.Подразделение.Тип.Типы().Количество() = 1
		И Метаданные.ОпределяемыеТипы.Подразделение.Тип.Типы()[0] = Тип("Строка") Тогда
		СписокИсключаемыхРеквизитов = СписокИсключаемыхРеквизитов + ",Подразделение";
	КонецЕсли;
	
	РазвернутьРеквизит(ШаблоныСообщений.ИмяУзлаОбщихРеквизитов() + ".ТекущийПользователь", ОбщиеРеквизитыСтроки.Строки,, СписокИсключаемыхРеквизитов);
	
	Возврат ОбщиеРеквизиты;
	
КонецФункции

Процедура ДобавитьОбщийРеквизит(ОбщиеРеквизиты, Имя, Представление, Тип = Неопределено)
	
	НовыйРеквизит = ОбщиеРеквизиты.Строки.Добавить();
	НовыйРеквизит.Имя = ШаблоныСообщений.ИмяУзлаОбщихРеквизитов() + "." + Имя;
	НовыйРеквизит.Представление = Представление;
	НовыйРеквизит.ПолноеПредставление = ЗаголовокОбщиеРеквизиты() + "." + Представление;
	НовыйРеквизит.Тип =?(Тип = Неопределено, Новый ОписаниеТипов("Строка"), Тип);
	
КонецПроцедуры

Функция ДобавитьРеквизит(Знач Имя, Узел)
	
	ИмяУзла = Узел.Родитель.Имя;
	Если НЕ СтрНачинаетсяС(Имя, ИмяУзла + ".") Тогда
		Имя = ИмяУзла + "." + Имя;
	КонецЕсли;
	
	НовыйРеквизит = Узел.Добавить();
	НовыйРеквизит.Имя = Имя;
	НовыйРеквизит.Представление = Имя;
	
	Возврат НовыйРеквизит;
	
КонецФункции

Функция РазвернутьРеквизит(Знач Имя, Узел, СписокРеквизитов = "", ИсключаяРеквизиты = "") Экспорт
	
	Реквизит = Узел.Найти(Имя, "Имя", Ложь);
	Если Реквизит <> Неопределено Тогда
		РазвернутьРеквизитПоМетаданнымОбъекта(Реквизит, СписокРеквизитов, ИсключаяРеквизиты, Имя);
	Иначе
		Имя = Узел.Родитель.Имя + "." + Имя;
		Реквизит = Узел.Найти(Имя, "Имя", Ложь);
		Если СтрЧислоВхождений(Имя, ".") > 1 Тогда
			Возврат Реквизит.Строки;
		КонецЕсли;
		
		Если Реквизит <> Неопределено Тогда
			РазвернутьРеквизитПоМетаданнымОбъекта(Реквизит, СписокРеквизитов, ИсключаяРеквизиты, Имя);
		КонецЕсли;
	КонецЕсли;
	
	Возврат Реквизит.Строки;
	
КонецФункции

Процедура РазвернутьРеквизитПоМетаданнымОбъекта(Реквизит, СписокРеквизитов, ИсключаяРеквизиты, Знач Префикс)
	
	Если ТипЗнч(Реквизит.Тип) = Тип("ОписаниеТипов") Тогда
		УзелРеквизитов = Реквизит.Строки;
		Префикс = Префикс + ?(Прав(Префикс, 1) <> ".", ".", "");
		Для каждого Тип Из Реквизит.Тип.Типы() Цикл
			МетаданныеОбъект = Метаданные.НайтиПоТипу(Тип);
			Если МетаданныеОбъект <> Неопределено Тогда
				РеквизитыПоМетаданнымОбъекта(УзелРеквизитов, МетаданныеОбъект, СписокРеквизитов, ИсключаяРеквизиты, Префикс);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// Файлы
Процедура ДобавитьПрисоединенныеФайлыВоВложения(Знач ПараметрыОтправки, Знач Сообщение)
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайлами = ОбщегоНазначения.ОбщийМодуль("РаботаСФайлами");
		СписокПрисоединенныхФайлов = Новый Массив; // Массив из ОпределяемыйТип.ПрисоединенныйФайл
		МодульРаботаСФайлами.ЗаполнитьПрисоединенныеФайлыКОбъекту(ПараметрыОтправки.Шаблон, СписокПрисоединенныхФайлов);
		
		Для каждого ПрисоединенныйФайл Из СписокПрисоединенныхФайлов Цикл
			Если ПустаяСтрока(ПрисоединенныйФайл.ИДФайлаЭлектронногоПисьма) Тогда
				ОписаниеФайла = МодульРаботаСФайлами.ДанныеФайла(ПрисоединенныйФайл.Ссылка, ПараметрыОтправки.УникальныйИдентификатор);
				Если Прав(ОписаниеФайла.ИмяФайла, 1) = "." Тогда
					ОписаниеФайлаИмяФайла = Лев(ОписаниеФайла.ИмяФайла, СтрДлина(ОписаниеФайла.ИмяФайла) - 1);
				Иначе
					ОписаниеФайлаИмяФайла = ОписаниеФайла.ИмяФайла;
				КонецЕсли;
				Сообщение.Вложения.Вставить(ОписаниеФайлаИмяФайла,  ОписаниеФайла.СсылкаНаДвоичныеДанныеФайла);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

КонецПроцедуры

// Получает заголовок системы, а если он не задан - синоним метаданных конфигурации.
Функция ИмяЭтойИнформационнойБазы()
	
	УстановитьПривилегированныйРежим(Истина);
	
	Результат = Константы.ЗаголовокСистемы.Получить();
	
	Если ПустаяСтрока(Результат) Тогда
		
		Результат = Метаданные.Синоним;
		
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция ВнешняяСсылкаНаОбъект(Параметр)
	
	Возврат ОбщегоНазначения.АдресПубликацииИнформационнойБазыВИнтернете() + "#" +  ПолучитьНавигационнуюСсылку(Параметр);
	
КонецФункции

Процедура ЗаполнитьПолучателейСообщения(ПараметрыОтправки, ПараметрыШаблона, Результат, МенеджерОбъекта)
	
	Если ПараметрыОтправки.Свойство("ДополнительныеПараметры")
		И ПараметрыОтправки.ДополнительныеПараметры.Свойство("ПроизвольныеПараметры") Тогда
		
		ПредметСообщения = Новый Структура("Предмет, ПроизвольныеПараметры");
		ПредметСообщения.Предмет               = ПараметрыОтправки.Предмет;
		ПредметСообщения.ПроизвольныеПараметры = ПараметрыОтправки.ДополнительныеПараметры.ПроизвольныеПараметры;
		ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ПредметСообщения, ПараметрыОтправки.ДополнительныеПараметры, Ложь);
		
	Иначе
		
		ПредметСообщения = ПараметрыОтправки.Предмет;
		
	КонецЕсли;
	
	Если ПараметрыШаблона.ТипШаблона = "Письмо" Тогда
		Получатели = СформироватьПолучателейПоУмолчанию(ПараметрыОтправки.Предмет, ПараметрыШаблона.ТипШаблона);
		ШаблоныСообщенийПереопределяемый.ПриЗаполненииПочтыПолучателейВСообщении(Получатели, ПараметрыШаблона.ПолноеИмяТипаНазначения, ПредметСообщения);
		Если МенеджерОбъекта <> Неопределено Тогда
				МенеджерОбъекта.ПриЗаполненииПочтыПолучателейВСообщении(Получатели, ПредметСообщения);
		КонецЕсли;
		
		Если ПараметрыШаблона.Свойство("РасширенныйСписокПолучателей")
			И ПараметрыШаблона.РасширенныйСписокПолучателей Тогда
			
			Результат.Получатель = Новый Массив;
			Для каждого Получатель Из Получатели Цикл
				Если ЗначениеЗаполнено(Получатель.Адрес) Тогда
					
					ЗначениеПолучателя = ШаблоныСообщений.НовыйПолучателиПисьма();
					ЗначениеПолучателя.Адрес                        = Получатель.Адрес;
					ЗначениеПолучателя.Представление                = Получатель.Представление;
					ЗначениеПолучателя.ИсточникКонтактнойИнформации = Получатель.Контакт;
				
					ЗначениеПолучателя.Вставить("ВариантОтправки", Получатель.ВариантОтправки);
					Результат.Получатель.Добавить(ЗначениеПолучателя);
				КонецЕсли;
			КонецЦикла;
			
		Иначе
			
			Результат.Получатель = Новый СписокЗначений();
			Для каждого Получатели Из Получатели Цикл
				Если ЗначениеЗаполнено(Получатели.Адрес) Тогда
					Результат.Получатель.Добавить(Получатели.Адрес, Получатели.Представление);
				КонецЕсли;
			КонецЦикла;
			
		КонецЕсли;
		
	Иначе
		
		Получатели = СформироватьПолучателейПоУмолчанию(ПараметрыОтправки.Предмет, ПараметрыШаблона.ТипШаблона);
		ШаблоныСообщенийПереопределяемый.ПриЗаполненииТелефоновПолучателейВСообщении(Получатели, ПараметрыШаблона.ПолноеИмяТипаНазначения, ПредметСообщения);
		Если МенеджерОбъекта <> Неопределено Тогда
			МенеджерОбъекта.ПриЗаполненииТелефоновПолучателейВСообщении(Получатели, ПредметСообщения);
		КонецЕсли;
		
		РасширенныйСписокПолучателей = ПараметрыОтправки.ДополнительныеПараметры.Свойство("РасширенныйСписокПолучателей") И ПараметрыОтправки.ДополнительныеПараметры.РасширенныйСписокПолучателей;
		
		Если РасширенныйСписокПолучателей Или (ПараметрыШаблона.Свойство("РасширенныйСписокПолучателей")
			И ПараметрыШаблона.РасширенныйСписокПолучателей) Тогда
			
			Результат.Получатель = Новый Массив;
			Для каждого Получатель Из Получатели Цикл
				Если ЗначениеЗаполнено(Получатель.НомерТелефона) Тогда
					ЗначениеПолучателя = Новый Структура("НомерТелефона, Представление, ИсточникКонтактнойИнформации", 
					Получатель.НомерТелефона, Получатель.Представление, Получатель.Контакт);
					Результат.Получатель.Добавить(ЗначениеПолучателя);
				КонецЕсли;
			КонецЦикла;
			
		Иначе
			
			Результат.Получатель = Новый СписокЗначений;
			Для каждого Получатели Из Получатели Цикл
				Если ЗначениеЗаполнено(Получатели.НомерТелефона) Тогда
					Результат.Получатель.Добавить(Получатели.НомерТелефона, Получатели.Представление);
				КонецЕсли;
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

Функция СформироватьПолучателейПоУмолчанию(Предмет, ТипШаблона);
	
	Получатели = Новый ТаблицаЗначений;
	Получатели.Колонки.Добавить("ВариантОтправки", ОбщегоНазначения.ОписаниеТипаСтрока(20));
	Получатели.Колонки.Добавить("Представление", ОбщегоНазначения.ОписаниеТипаСтрока(0));
	Получатели.Колонки.Добавить("Контакт");
	Если СтрСравнить(ТипШаблона, "SMS") = 0 Тогда
		Получатели.Колонки.Добавить("НомерТелефона", ОбщегоНазначения.ОписаниеТипаСтрока(500));
		ИмяКолонки = "НомерТелефона";
	Иначе
		Получатели.Колонки.Добавить("Адрес", Новый ОписаниеТипов("Строка"));
		ИмяКолонки = "Адрес";
	КонецЕсли;
	
	Если Предмет = Неопределено Тогда
		Возврат Получатели;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
		
		ТипКонтактнойИнформации = ?(СтрСравнить(ТипШаблона, "SMS") = 0,
			МодульУправлениеКонтактнойИнформацией.ТипКонтактнойИнформацииПоНаименованию("Телефон"),
			МодульУправлениеКонтактнойИнформацией.ТипКонтактнойИнформацииПоНаименованию("АдресЭлектроннойПочты"));
	
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Взаимодействия") Тогда
				МодульВзаимодействия = ОбщегоНазначения.ОбщийМодуль("Взаимодействия");
				
				Если МодульВзаимодействия.ИспользуетсяПочтовыйКлиент() Тогда
					Контакты = МодульВзаимодействия.ПолучитьКонтактыПоПредмету(Предмет, ТипКонтактнойИнформации);
					
					Для каждого ИнформацияОКонтакте Из Контакты Цикл
						НоваяСтрока = Получатели.Добавить();
						НоваяСтрока.ВариантОтправки = "Кому";
						НоваяСтрока.Контакт         = ИнформацияОКонтакте.Контакт;
						НоваяСтрока.Представление   = ИнформацияОКонтакте.Представление;
						НоваяСтрока[ИмяКолонки]     = ИнформацияОКонтакте.Адрес;
					КонецЦикла;
				КонецЕсли;
				
		КонецЕсли;
	
		// Если список контактов пустой, а у объекта есть контактная информация.
		Если Получатели.Количество() = 0 И ТипЗнч(Предмет) <> Тип("Строка") Тогда
			ОбъектыСКонтактнойИнформацией = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Предмет);
			
			ВидыКонтактнойИнформацииОбъекта = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(Предмет);
			Если ВидыКонтактнойИнформацииОбъекта.Количество() > 0 Тогда
				КонтактнаяИнформацияОбъектов = МодульУправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъектов(ОбъектыСКонтактнойИнформацией, ТипКонтактнойИнформации,, ТекущаяДатаСеанса());
				Если КонтактнаяИнформацияОбъектов.Количество() > 0 Тогда
					Для каждого КонтактнаяИнформацияОбъекта Из КонтактнаяИнформацияОбъектов Цикл
						НоваяСтрока= Получатели.Добавить();
						НоваяСтрока.ВариантОтправки = "Кому";
						НоваяСтрока[ИмяКолонки]     = КонтактнаяИнформацияОбъекта.Представление;
						НоваяСтрока.Представление   = СтрЗаменить(Строка(КонтактнаяИнформацияОбъекта.Объект), ",", "");
						НоваяСтрока.Контакт         = Предмет;
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Возврат Получатели;
	
КонецФункции

Функция СкопироватьСоответствие(Источник)
	
	Получатель = Новый Соответствие;
	
	Для каждого Элемент Из Источник Цикл
		Если ТипЗнч(Элемент.Значение) = Тип("Соответствие") Тогда
			Получатель[Элемент.Ключ] = СкопироватьСоответствие(Элемент.Значение);
		Иначе
			Получатель[Элемент.Ключ] = Элемент.Значение;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Получатель;
	
КонецФункции

Функция ИмяСобытияЖурналаРегистрации()
	
	Возврат НСтр("ru = 'Формирование шаблона сообщений'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

Процедура СформироватьСообщениеВФоне(ПараметрыВызоваСервера, АдресХранилища, СформироватьИОтправить) Экспорт
	
	ПараметрыОтправки = ПараметрыВызоваСервера.ПараметрыОтправки; // см. ШаблоныСообщенийКлиентСервер.КонструкторПараметровОтправки
	ВидСообщения = ПараметрыВызоваСервера.ВидСообщения;
	
	Если СформироватьИОтправить Тогда
		Результат = СформироватьСообщениеИОтправить(ПараметрыОтправки);
		ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
	Иначе
		
		ПараметрыШаблона = ШаблоныСообщений.СформироватьПараметрыОтправки(ПараметрыОтправки.Шаблон, ПараметрыОтправки.Предмет,
			ПараметрыОтправки.УникальныйИдентификатор, ПараметрыОтправки.ДополнительныеПараметры.ПараметрыСообщения);
		
		ОбщегоНазначенияКлиентСервер.ДополнитьСтруктуру(ПараметрыШаблона.ДополнительныеПараметры,
			ПараметрыОтправки.ДополнительныеПараметры, Истина);
		
		Сообщение = СформироватьСообщение(ПараметрыШаблона);
		
		Если ВидСообщения = "Письмо" Тогда
			Сообщение = ПреобразоватьПараметрыПисьма(Сообщение);
		Иначе
			Сообщение.Вложения = Неопределено;
		КонецЕсли;
		
		ПоместитьВоВременноеХранилище(Сообщение, АдресХранилища);
	КонецЕсли;
	
КонецПроцедуры

Функция ПреобразоватьПараметрыПисьма(Сообщение)
	
	ПараметрыПисьма = Новый Структура();
	ПараметрыПисьма.Вставить("Отправитель");
	ПараметрыПисьма.Вставить("Тема", Сообщение.Тема);
	ПараметрыПисьма.Вставить("Текст", Сообщение.Текст);
	ПараметрыПисьма.Вставить("СообщенияПользователю", Сообщение.СообщенияПользователю);
	ПараметрыПисьма.Вставить("УдалятьФайлыПослеОтправки", Ложь);
	
	Если Сообщение.Получатель = Неопределено ИЛИ Сообщение.Получатель.Количество() = 0 Тогда
		ПараметрыПисьма.Вставить("Получатель", Неопределено);
	Иначе
		ПараметрыПисьма.Вставить("Получатель", Сообщение.Получатель);
	КонецЕсли;
	
	МассивВложений = Новый Массив;
	Для Каждого ОписаниеВложения Из Сообщение.Вложения Цикл
		ИнформацияОВложении = Новый Структура("Представление, АдресВоВременномХранилище, Кодировка, Идентификатор");
		ЗаполнитьЗначенияСвойств(ИнформацияОВложении, ОписаниеВложения);
		МассивВложений.Добавить(ИнформацияОВложении);
	КонецЦикла;
	ПараметрыПисьма.Вставить("Вложения", МассивВложений);
	
	Возврат ПараметрыПисьма;
	
КонецФункции

// Обновление

// Добавляет роль ДобавлениеИзменениеЛичныхШаблоновСообщений во все профили, в которые входит роль БазовыеПраваБСП.
Процедура ДобавитьРольДобавлениеИзменениеЛичныхШаблоновВПрофилиСБазовымиПравами() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;
	
	МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
	
	НовыеРоли = Новый Массив;
	НовыеРоли.Добавить(Метаданные.Роли.БазовыеПраваБСП.Имя);
	НовыеРоли.Добавить(Метаданные.Роли.ДобавлениеИзменениеЛичныхШаблоновСообщений.Имя);
	
	ЗаменяемыеРоли = Новый Соответствие;
	ЗаменяемыеРоли.Вставить(Метаданные.Роли.БазовыеПраваБСП.Имя, НовыеРоли);
	
	МодульУправлениеДоступом.ЗаменитьРолиВПрофилях(ЗаменяемыеРоли);
	
КонецПроцедуры

Функция ЭтоСтандартныйРеквизит(МетаданныеОбъекта, ИмяРеквизита) Экспорт
	
	Для Каждого СтандартныйРеквизит Из МетаданныеОбъекта.СтандартныеРеквизиты Цикл
		
		Если СтрСравнить(СтандартныйРеквизит.Имя, ИмяРеквизита) = 0 Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

#КонецОбласти